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 );
}
}
This is a bug in
TableViewSkin
.In Java 8, the method
resizeColumnToFitContent
, which is invoked by double clicking a column separator, does not callresizeColumn
inTableView
. 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 overridingresizeColumnToFitContent
: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.