By default, a JavaFX TableView has a column policy of UNCONSTRAINED_RESIZE_POLICY. This means that the TableView will rely on the explicit specifications of the TableColumns. This screenshot shows 3 columns each with different preferredWidth properties: 50, 100, and 100, respectively. Notice the extra space after the Data TableColumn to the right.
Unconstrained TableView Resize Policy |
Constrained TableView Resize Policy |
This program uses JavaFX binding to link the Preferred Width property of the last column to the available space as calculated by TABLE WIDTH - SUM(OTHER COLUMNS). The binding expression is.
tcData.prefWidthProperty().bind( tbl.widthProperty() .subtract(tcIcon.widthProperty()) .subtract(tcText.widthProperty()) .subtract(2) // a border stroke? );
tcIcon, tcText, and tcData are 3 columns. tcIcon is fixed. tcText and tcData are resizable. tcData is expected to acquire any available space when the screen is displayed or if the screen is resized.
The result is a TableView that honors the preferredWidth settings for all but the last TableColumn.
TableView with Last TableColumn Width Based on an Expression |
This class is followed with a definition of RowType which must be public so that the PropertyValueFactories will work.
public class TableResizeApp extends Application { private final ObservableList<RowType> rows = FXCollections.observableArrayList(); @Override public void start(Stage primaryStage) throws Exception { rows.add( new RowType("a", "b", "c")); rows.add( new RowType("1", "2", "3") ); rows.add( new RowType("X", "Y", "Z")); // not using constrained policy TableView<RowType> tbl = new TableView<>); TableColumn<RowType, String> tcIcon = new TableColumn<>("Icon"); TableColumn<RowType, String> tcText = new TableColumn<>("Text"); TableColumn<RowType, String> tcData = new TableColumn<>("Data"); tcIcon.setResizable(false); tcIcon.setPrefWidth( 50.0d ); tcText.setPrefWidth(100.0d); tcData.setPrefWidth(100.0d); tcIcon.setCellValueFactory( new PropertyValueFactory<RowType, String>("icon") ); tcText.setCellValueFactory( new PropertyValueFactory<RowType, String>("text") ); tcData.setCellValueFactory( new PropertyValueFactory<RowType, String>("data") ); tcData.prefWidthProperty().bind( tbl.widthProperty() .subtract(tcIcon.widthProperty()) .subtract(tcText.widthProperty()) .subtract(2) // a border stroke? ); tbl.getColumns().add( tcIcon ); tbl.getColumns().add( tcText ); tbl.getColumns().add( tcData ); tbl.itemsProperty().bind( new SimpleObjectProperty<gt&(rows) ); Scene scene = new Scene(tbl); primaryStage.setScene( scene ); primaryStage.setWidth( 667 ); primaryStage.setHeight( 375 ); primaryStage.show(); }
And this is the JavaBean for the TableView.
public class RowType { private String icon; private String text; private String data; public RowType() {} public RowType(String icon, String text, String data) { this.icon = icon; this.text = text; this.data = data; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
Hi,
ReplyDeleteThis didn't work for me. I put the code in a stage.onShown() and tried a few resize policies. Note that the binding syntax also accounts for width changes to the overall window.
You can probably also remove the Platform.runLater() since the iteration is likely already on the FX Thread.
Hello! It worked for me! Thanks a lot! Greetings from Brazil.
ReplyDeleteHi
ReplyDeleteis there a way for the first and the last column be constraint and the middle column have a fix size?
Sure. Replace the tcData expression with the following which will apply binding to the first and last columns.
DeletetcIcon.prefWidthProperty().bind(
tbl.widthProperty()
.subtract(tcText.widthProperty())
.divide(2)
.subtract(1) // a border stroke?
);
tcData.prefWidthProperty().bind(
tbl.widthProperty()
.subtract(tcText.widthProperty())
.divide(2)
.subtract(1) // a border stroke?
);
It's a good solution, BUT if width of your first or second column would be too big (if you scroll it manuell), "tcData" goes abroad TableView:(
ReplyDeleteJust set a min width so that tcData won't disappear
DeletetcData.setMinWidth(100.0d);
Found an easy solution that works with CONSTRAINED_RESIZE_POLICY : just set minWidth and maxWidth to the same value on components you do not want to expand.
ReplyDeleteJules that helped a lot. Thanks.
ReplyDelete