ADDITIONAL SYSTEM INFORMATION :
MacOS 12.6.1, x86_64, Java 11 LTS, JavaFX 19.0.1.
A DESCRIPTION OF THE PROBLEM :
Normally, calling tableView.scrollTo(tableView.size() - 1) will scroll the table to the bottom, leaving the last row at the bottom of the viewport. As of Java 19, if the displayed list is "big enough", the call will scroll so that the last row is displayed at the *top* of the viewport, leaving the rest of the viewport blank. Scrolling via key or scrollbar mouse-click will then restore it to its normal appearance.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the source code below. It creates a small JavaFX app containing a TableView and two buttons, "Add 100 Entries" and "Scroll to Bottom". Press "Add 100 Entries" 3 times, and then press "Scroll to Bottom". This results in the error 100% of the time in our experience.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"Scroll to bottom" should do nothing if the last row is already visible, and should scroll so that it is displayed at the bottom of the viewport if not. (This is the historical behavior.)
ACTUAL -
The last row is displayed at the top of the viewport, leaving the rest of the viewport blank.
In this case we see this error:
Nov 09, 2022 9:47:44 AM javafx.scene.control.skin.VirtualFlow addTrailingCells
INFO: index exceeds maxCellCount. Check size calculations for class javafx.scene.control.TableRow
---------- BEGIN SOURCE ----------
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package app;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* This app illustrates a TableView bug. If the TableView contains enough
* rows (somewhere between 200 and 300 in my experience), then a call to
* TableView::scrollTo for the index of the last row will cause the
* last row to appear at the top of the view port with blank space below,
* instead of at the bottom of the view port as expected.
*
* <p>To see the bug: press "Add 100 Items" followed by "Scroll to Bottom"
* repeatedly.</p>
*/
public class App extends Application {
private final ObservableList<Record> records =
FXCollections.observableArrayList();
private final TableView<Record> tableView = new TableView<>();
public void start(Stage stage) {
VBox hull = new VBox();
ToolBar toolbar = new ToolBar();
Button add100Button = new Button("Add 100 Items");
add100Button.setOnAction(evt -> addOneHundredItems());
toolbar.getItems().add(add100Button);
Button scrollButton = new Button("Scroll to Bottom");
scrollButton.setOnAction(evt -> {
if (!tableView.getItems().isEmpty()) {
int ndx = tableView.getItems().size() - 1;
System.out.println("TableView contains " +
tableView.getItems().size() + " elements.");
System.out.println("Scrolling to index " + ndx);
tableView.scrollTo(ndx);
}
});
toolbar.getItems().add(scrollButton);
hull.getChildren().add(toolbar);
tableView.setItems(records);
TableColumn<Record,String> nameColumn = new TableColumn<>();
nameColumn.setText("Name");
nameColumn.setPrefWidth(150);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
tableView.getColumns().add(nameColumn);
TableColumn<Record,String> valueColumn = new TableColumn<>();
valueColumn.setText("Value");
valueColumn.setPrefWidth(150);
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
tableView.getColumns().add(valueColumn);
hull.getChildren().add(tableView);
// NEXT, set up the scene.
Scene scene = new Scene(hull, 400, 300);
stage.setTitle("TableView Scrolling");
stage.setScene(scene);
// FINALLY, show the GUI.
stage.show();
}
private void addOneHundredItems() {
for (int i = 0; i < 100; i++) {
int size = records.size();
records.add(new Record("Name " + size, "Value " + size));
}
System.out.println("Table contains " + records.size() + " items");
}
public static class Record {
private final String name;
private final String value;
Record(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() { return name; }
public String getValue() { return value; }
}
public static void main(String[] args) {
launch(args);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None.
FREQUENCY : always
MacOS 12.6.1, x86_64, Java 11 LTS, JavaFX 19.0.1.
A DESCRIPTION OF THE PROBLEM :
Normally, calling tableView.scrollTo(tableView.size() - 1) will scroll the table to the bottom, leaving the last row at the bottom of the viewport. As of Java 19, if the displayed list is "big enough", the call will scroll so that the last row is displayed at the *top* of the viewport, leaving the rest of the viewport blank. Scrolling via key or scrollbar mouse-click will then restore it to its normal appearance.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the source code below. It creates a small JavaFX app containing a TableView and two buttons, "Add 100 Entries" and "Scroll to Bottom". Press "Add 100 Entries" 3 times, and then press "Scroll to Bottom". This results in the error 100% of the time in our experience.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"Scroll to bottom" should do nothing if the last row is already visible, and should scroll so that it is displayed at the bottom of the viewport if not. (This is the historical behavior.)
ACTUAL -
The last row is displayed at the top of the viewport, leaving the rest of the viewport blank.
In this case we see this error:
Nov 09, 2022 9:47:44 AM javafx.scene.control.skin.VirtualFlow addTrailingCells
INFO: index exceeds maxCellCount. Check size calculations for class javafx.scene.control.TableRow
---------- BEGIN SOURCE ----------
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package app;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* This app illustrates a TableView bug. If the TableView contains enough
* rows (somewhere between 200 and 300 in my experience), then a call to
* TableView::scrollTo for the index of the last row will cause the
* last row to appear at the top of the view port with blank space below,
* instead of at the bottom of the view port as expected.
*
* <p>To see the bug: press "Add 100 Items" followed by "Scroll to Bottom"
* repeatedly.</p>
*/
public class App extends Application {
private final ObservableList<Record> records =
FXCollections.observableArrayList();
private final TableView<Record> tableView = new TableView<>();
public void start(Stage stage) {
VBox hull = new VBox();
ToolBar toolbar = new ToolBar();
Button add100Button = new Button("Add 100 Items");
add100Button.setOnAction(evt -> addOneHundredItems());
toolbar.getItems().add(add100Button);
Button scrollButton = new Button("Scroll to Bottom");
scrollButton.setOnAction(evt -> {
if (!tableView.getItems().isEmpty()) {
int ndx = tableView.getItems().size() - 1;
System.out.println("TableView contains " +
tableView.getItems().size() + " elements.");
System.out.println("Scrolling to index " + ndx);
tableView.scrollTo(ndx);
}
});
toolbar.getItems().add(scrollButton);
hull.getChildren().add(toolbar);
tableView.setItems(records);
TableColumn<Record,String> nameColumn = new TableColumn<>();
nameColumn.setText("Name");
nameColumn.setPrefWidth(150);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
tableView.getColumns().add(nameColumn);
TableColumn<Record,String> valueColumn = new TableColumn<>();
valueColumn.setText("Value");
valueColumn.setPrefWidth(150);
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
tableView.getColumns().add(valueColumn);
hull.getChildren().add(tableView);
// NEXT, set up the scene.
Scene scene = new Scene(hull, 400, 300);
stage.setTitle("TableView Scrolling");
stage.setScene(scene);
// FINALLY, show the GUI.
stage.show();
}
private void addOneHundredItems() {
for (int i = 0; i < 100; i++) {
int size = records.size();
records.add(new Record("Name " + size, "Value " + size));
}
System.out.println("Table contains " + records.size() + " items");
}
public static class Record {
private final String name;
private final String value;
Record(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() { return name; }
public String getValue() { return value; }
}
public static void main(String[] args) {
launch(args);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None.
FREQUENCY : always
- duplicates
-
JDK-8301375 Cell is not displayed when scrolling to the end of ListView with many cells.
-
- Closed
-
- relates to
-
JDK-8291908 VirtualFlow creates unneeded empty cells
-
- Resolved
-
-
JDK-8328167 ScrollTo in ListView still doesn't work since VirtualFlow was modified
-
- Open
-