4

I wrote a custom resize policy for a TableView which is similar to TableView.CONSTRAINED_RESIZE_POLICY in that the total width of visible columns always equals the width of the table itself.

Whenever a column is resized, either by the table being resized or the user dragging the column, the resize policy is called and the columns are resized appropriately.

However, when one of the dividers in the table's header is double-clicked (to "shrink wrap" the column's content) the custom resize policy isn't triggered.

As a result, the total width of the columns can be more or less than the table's width, which is not good.

How can I detect these double clicks and cause my CustomResizePolicy to trigger a call afterwards?

Here is a working example showing the double clicks do not result in a call to the CustomResizePolicy:

import java.util.Locale;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class CustomResizeExample extends Application {

    @SuppressWarnings("unchecked")
    private Parent getContent () {
        TableView <Locale> table = new TableView <>( FXCollections.observableArrayList( Locale.getAvailableLocales() ) );
        TableColumn <Locale, String> countryCode = new TableColumn <>( "CountryCode" );
        countryCode.setCellValueFactory( new PropertyValueFactory <>( "country" ) );
        TableColumn <Locale, String> language = new TableColumn <>( "Language" );
        language.setCellValueFactory( new PropertyValueFactory <>( "language" ) );
        table.getColumns().addAll( countryCode, language );

        TableColumn <Locale, Locale> local = new TableColumn <>( "Locale" );
        local.setCellValueFactory( c -> new SimpleObjectProperty <>( c.getValue() ) );

        table.getColumns().addAll( local );
        table.setColumnResizePolicy( new CustomResizePolicy() );

        BorderPane pane = new BorderPane( table );
        return pane;
    }
    @Override
    public void start ( Stage stage ) throws Exception {
        stage.setScene( new Scene( getContent(), 800, 400 ) );
        stage.show();
    }

    public static void main ( String[] args ) {
        launch ( args );
    }

}

@SuppressWarnings ( "rawtypes" ) 
class CustomResizePolicy implements Callback <TableView.ResizeFeatures, Boolean> {
    @Override
    public Boolean call ( TableView.ResizeFeatures feature ) {

        System.out.println ( "Called" ); //This does not print when the divider is double-clicked.

        return TableView.CONSTRAINED_RESIZE_POLICY.call( feature );
    }
}

1 Answer 1

3

This is a bug in TableViewSkin.

In Java 8, the method resizeColumnToFitContent, which is invoked by double clicking a column separator, does not call resizeColumn in TableView. The result is that the layout is not updated correctly. It's enough that you try to resize a fit-to-width column to observe this. In fact, fitting-to-width repeatedly will set the width closer and closer to its real width. Try to fit and then resize several times in a row the same column (doing this with other columns will reset the behavior).

I didn't have time to find a good workaround. There's some semblance of improvement by subclassing TableViewSkin and overriding resizeColumnToFitContent:

class CustomTableSkin<T> extends TableViewSkin<T> {

    public CustomTableSkin(TableView<T> tableView) {
        super(tableView);
        i = tableView.getColumns().size() + 1;
    }

    private int i;

    @Override
    protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
        double before = tc.getWidth();
        super.resizeColumnToFitContent(tc, maxRows);
        double now = tc.getWidth();
        double diff = before - now;
        i--;
        if (i >= 0)
            resizeColumn(tc, -diff);
    }
}

The addition of calls to resizeColumn help in some cases, but it will take some more research to find out the correct fix.

Java 9 changed the skinning implementation, though I believe the problem is still present there.

Sign up to request clarification or add additional context in comments.

I am not able to find CustomTableSkin in java 8. Did I misunderstand your post?
Er. I mean I can't find "TableViewSkin" in my java -- openjdk version "1.8.0_151". When I try to "import com.sun.javafx.scene.control.TableViewSkin" I get "The import cannot be resolved.
@JoshuaD Google should help you with that.
I googled it before posting, both times. I will try a third time. In the meantime, if you have the answer, it would be helpful to edit it into your post, as I'm sure I won't be the only person running into that problem, and I promise it is not readily apparent how to use your proposed solution.
I'm looking at the javafx 8 javadoc and I don't see it: i.imgur.com/E3oevLH.png, docs.oracle.com/javase/8/javafx/api/toc.htm

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.