Details
Description
Since updating 8u20 b13, I've noticed that our app's TableView does not appear to be refreshing its cells properly. It seems like when the ObservableValue for a cell changes, the cell itself won't update until I scroll the cell off screen and then back on screen again.
Run the following sample code:
import javafx.application.Application;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TableRefreshBug extends Application {
// boilerplate to build table, add it to a stage, and show stage
public static void main(String[] args) {
launch(args);
}
@Override public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add( buildTable() );
primaryStage.setScene(new Scene(root, 250, 250));
primaryStage.show();
}
ObjectProperty<Integer> offset_ = new SimpleObjectProperty<Integer>(0);
private TableView buildTable() {
// create table with a bunch of rows and 1 column...
TableView<Integer> table = new TableView<>();
for ( int i = 1; i <= 50; i++ ) {
table.getItems().add(i);
}
final TableColumn<Integer, Integer> column = new TableColumn<>("Column");
table.getColumns().add( column );
column.setPrefWidth( 150 );
// each cell displays x, where x = "cell row number + offset"
column.setCellValueFactory( cdf -> new ObjectBinding<Integer>() {
{ super.bind( offset_ ); }
@Override protected Integer computeValue() {
return cdf.getValue() + offset_.get();
}
});
// offset starts at 0, but increments any time you click on the table
table.setOnMouseClicked( e ->
{ offset_.set( offset_.get()+1 );
System.out.println("clicked. offset=" + offset_); } );
return table;
}
}
---------------------
This will open a window with a scrollable table that contains 50 rows and 1 column. Each cell displays an integer, which is just its row number + a special offset value. Initially, the offset value is 0, so you'll just see the row numbers.
Here's the steps to see the bug:
1) scroll the table up and down a bit.
2) click repeatedly anywhere on the table.
3) goto step 1
Each time you click, you increase the value of offset, which should automatically increment the value in every cell. This is exactly what happens if you run the example using the Java 8 public release or and early build of 8u20.
But now run the code on 8u20 b13. You'll notice that the numbers don't update after step 2, they only update once you get back to step 1 (scrolling must force a refresh or something.)
Interestingly, in this example the bug won't happen until you scroll the table a bit. If you never scroll, everything seems to work fine. But in my own app, which has a much more complicated table, the bug happens right away, even before scrolling.
Run the following sample code:
import javafx.application.Application;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TableRefreshBug extends Application {
// boilerplate to build table, add it to a stage, and show stage
public static void main(String[] args) {
launch(args);
}
@Override public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add( buildTable() );
primaryStage.setScene(new Scene(root, 250, 250));
primaryStage.show();
}
ObjectProperty<Integer> offset_ = new SimpleObjectProperty<Integer>(0);
private TableView buildTable() {
// create table with a bunch of rows and 1 column...
TableView<Integer> table = new TableView<>();
for ( int i = 1; i <= 50; i++ ) {
table.getItems().add(i);
}
final TableColumn<Integer, Integer> column = new TableColumn<>("Column");
table.getColumns().add( column );
column.setPrefWidth( 150 );
// each cell displays x, where x = "cell row number + offset"
column.setCellValueFactory( cdf -> new ObjectBinding<Integer>() {
{ super.bind( offset_ ); }
@Override protected Integer computeValue() {
return cdf.getValue() + offset_.get();
}
});
// offset starts at 0, but increments any time you click on the table
table.setOnMouseClicked( e ->
{ offset_.set( offset_.get()+1 );
System.out.println("clicked. offset=" + offset_); } );
return table;
}
}
---------------------
This will open a window with a scrollable table that contains 50 rows and 1 column. Each cell displays an integer, which is just its row number + a special offset value. Initially, the offset value is 0, so you'll just see the row numbers.
Here's the steps to see the bug:
1) scroll the table up and down a bit.
2) click repeatedly anywhere on the table.
3) goto step 1
Each time you click, you increase the value of offset, which should automatically increment the value in every cell. This is exactly what happens if you run the example using the Java 8 public release or and early build of 8u20.
But now run the code on 8u20 b13. You'll notice that the numbers don't update after step 2, they only update once you get back to step 1 (scrolling must force a refresh or something.)
Interestingly, in this example the bug won't happen until you scroll the table a bit. If you never scroll, everything seems to work fine. But in my own app, which has a much more complicated table, the bug happens right away, even before scrolling.