-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
None
-
jfx24
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
JavaFX 24 running on OpenJDK 24
A DESCRIPTION OF THE PROBLEM :
When using a TableView as the content on a Tab, calling the table's refresh() method is not sufficient to rebuild the cells of that table. This can be traced back to the fact that TabPaneSkin's layoutChildren() is only calling resize() and relocate() on the Tab contents, and in the case where the width/height/x/y don't actually change, basically nothing happens. But in this case, the TableView needs it's layoutChildren() to be called for the sole reason that it needs to recreate cells. I expect that calling TableView refresh() should _guarantee_ a call to that table's layoutChildren() at the next pulse, but that's not always the case.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Set the content of a Tab to be a TableView. Set up the data for TableCells such that their content depends on external data changes (i.e. neither the row data or cell item). Start the application with the TableView visible on screen. Trigger the external data change. Then call TableView refresh().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The call to refresh() should cause the data to update at the next pulse.
ACTUAL -
The table's data remains stale because it's layoutChildren() never got called, so the flag set by refresh() basically accomplishes nothing until some future layout pass. That pass could happen too late to effectively honor the contract stated by the javadocs of the refresh() method.
---------- BEGIN SOURCE ----------
public void start(Stage stage)
{
var textField = new TextField("Initial Data");
var button = new Button("Refresh table");
var tableColumn = new TableColumn<TextField,String>("TextField's Text");
var tableView = new TableView<>(observableArrayList(List.of(textField)));
var tab = new Tab("Table", tableView);
var tabPane = new TabPane(tab);
var vbox = new VBox(
textField,
button,
tabPane
);
vbox.setStyle("-fx-padding: 20; -fx-spacing: 20; -fx-alignment: center;");
button.setOnAction(x -> tableView.refresh());
tableColumn.setCellValueFactory(f -> new SimpleStringProperty(f.getValue().getText()));
tableColumn.setPrefWidth(150);
tableView.getColumns().add(tableColumn);
stage.setTitle("Table refresh bug");
final Scene scene = new Scene(new StackPane(vbox), 400, 300);
stage.setScene(scene);
stage.show();
}
---------- END SOURCE ----------
JavaFX 24 running on OpenJDK 24
A DESCRIPTION OF THE PROBLEM :
When using a TableView as the content on a Tab, calling the table's refresh() method is not sufficient to rebuild the cells of that table. This can be traced back to the fact that TabPaneSkin's layoutChildren() is only calling resize() and relocate() on the Tab contents, and in the case where the width/height/x/y don't actually change, basically nothing happens. But in this case, the TableView needs it's layoutChildren() to be called for the sole reason that it needs to recreate cells. I expect that calling TableView refresh() should _guarantee_ a call to that table's layoutChildren() at the next pulse, but that's not always the case.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Set the content of a Tab to be a TableView. Set up the data for TableCells such that their content depends on external data changes (i.e. neither the row data or cell item). Start the application with the TableView visible on screen. Trigger the external data change. Then call TableView refresh().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The call to refresh() should cause the data to update at the next pulse.
ACTUAL -
The table's data remains stale because it's layoutChildren() never got called, so the flag set by refresh() basically accomplishes nothing until some future layout pass. That pass could happen too late to effectively honor the contract stated by the javadocs of the refresh() method.
---------- BEGIN SOURCE ----------
public void start(Stage stage)
{
var textField = new TextField("Initial Data");
var button = new Button("Refresh table");
var tableColumn = new TableColumn<TextField,String>("TextField's Text");
var tableView = new TableView<>(observableArrayList(List.of(textField)));
var tab = new Tab("Table", tableView);
var tabPane = new TabPane(tab);
var vbox = new VBox(
textField,
button,
tabPane
);
vbox.setStyle("-fx-padding: 20; -fx-spacing: 20; -fx-alignment: center;");
button.setOnAction(x -> tableView.refresh());
tableColumn.setCellValueFactory(f -> new SimpleStringProperty(f.getValue().getText()));
tableColumn.setPrefWidth(150);
tableView.getColumns().add(tableColumn);
stage.setTitle("Table refresh bug");
final Scene scene = new Scene(new StackPane(vbox), 400, 300);
stage.setScene(scene);
stage.show();
}
---------- END SOURCE ----------