On Thu, 3 Sep 2020 07:44:55 GMT, yosbits <github.com+7517141+yos...@openjdk.org> wrote:
>> If there are many columns, the current TableView will stall scrolling. >> Resolving this performance issue requires column virtualization. >> Virtualization mode is enabled when the row height is fixed by the following >> method. >> >> `tableView.setFixedCellSize(height)` >> >> This proposal includes a fix because the current code does not correctly >> implement column virtualization. >> >> The improvement of this proposal can be seen in the following test program. >> >> ``` Java >> import java.util.Arrays; >> import java.util.Collections; >> >> import javafx.animation.AnimationTimer; >> import javafx.application.Application; >> import javafx.beans.property.SimpleStringProperty; >> import javafx.collections.ObservableList; >> import javafx.scene.Scene; >> import javafx.scene.control.Button; >> import javafx.scene.control.TableColumn; >> import javafx.scene.control.TableView; >> import javafx.scene.layout.BorderPane; >> import javafx.scene.layout.HBox; >> import javafx.stage.Stage; >> >> public class BigTableViewTest2 extends Application { >> private static final boolean USE_WIDTH_FIXED_SIZE = false; >> private static final boolean USE_HEIGHT_FIXED_SIZE = true; >> // private static final int COL_COUNT=30; >> // private static final int COL_COUNT=300; >> // private static final int COL_COUNT=600; >> private static final int COL_COUNT = 1000; >> private static final int ROW_COUNT = 1000; >> >> @Override >> public void start(final Stage primaryStage) throws Exception { >> final TableView<String[]> tableView = new TableView<>(); >> >> // tableView.setTableMenuButtonVisible(true); //too heavy >> if (USE_HEIGHT_FIXED_SIZE) { >> tableView.setFixedCellSize(24); >> } >> >> final ObservableList<TableColumn<String[], ?>> columns = >> tableView.getColumns(); >> for (int i = 0; i < COL_COUNT; i++) { >> final TableColumn<String[], String> column = new >> TableColumn<>("Col" + i); >> final int colIndex = i; >> column.setCellValueFactory((cell) -> new >> SimpleStringProperty(cell.getValue()[colIndex])); >> columns.add(column); >> if (USE_WIDTH_FIXED_SIZE) { >> column.setPrefWidth(60); >> column.setMaxWidth(60); >> column.setMinWidth(60); >> } >> } >> >> final Button load = new Button("load"); >> load.setOnAction(e -> { >> final ObservableList<String[]> items = >> tableView.getItems(); >> items.clear(); >> for (int i = 0; i < ROW_COUNT; i++) { >> final String[] rec = new String[COL_COUNT]; >> for (int j = 0; j < rec.length; j++) { >> rec[j] = i + ":" + j; >> } >> items.add(rec); >> } >> }); >> >> final Button reverse = new Button("reverse columns"); >> reverse.setOnAction(e -> { >> final TableColumn<String[], ?>[] itemsArray = >> columns.toArray(new TableColumn[0]); >> Collections.reverse(Arrays.asList(itemsArray)); >> tableView.getColumns().clear(); >> >> tableView.getColumns().addAll(Arrays.asList(itemsArray)); >> }); >> >> final Button hide = new Button("hide % 10"); >> hide.setOnAction(e -> { >> for (int i = 0, n = columns.size(); i < n; i++) { >> if (i % 10 == 0) { >> columns.get(i).setVisible(false); >> } >> } >> }); >> >> final BorderPane root = new BorderPane(tableView); >> root.setTop(new HBox(8, load, reverse, hide)); >> >> final Scene scene = new Scene(root, 800, 800); >> primaryStage.setScene(scene); >> primaryStage.show(); >> this.prepareTimeline(scene); >> } >> >> public static void main(final String[] args) { >> Application.launch(args); >> } >> >> private void prepareTimeline(final Scene scene) { >> new AnimationTimer() { >> @Override >> public void handle(final long now) { >> final double fps = >> com.sun.javafx.perf.PerformanceTracker.getSceneTracker(scene).getInstantFPS(); >> ((Stage) scene.getWindow()).setTitle("FPS:" + >> (int) fps); >> } >> }.start(); >> } >> } >> >> >> ``` Java >> import javafx.animation.AnimationTimer; >> import javafx.application.Application; >> import javafx.application.Platform; >> import javafx.beans.property.ReadOnlyStringWrapper; >> import javafx.scene.Scene; >> import javafx.scene.control.TreeItem; >> import javafx.scene.control.TreeTableColumn; >> import javafx.scene.control.TreeTableColumn.CellDataFeatures; >> import javafx.scene.control.TreeTableView; >> import javafx.stage.Stage; >> >> public class BigTreeTableViewTest extends Application { >> >> private static final boolean USE_HEIGHT_FIXED_SIZE = true; >> // private static final int COL_COUNT = 900; >> private static final int COL_COUNT = 800; >> // private static final int COL_COUNT = 600; >> // private static final int COL_COUNT = 500; >> // private static final int COL_COUNT = 400; >> // private static final int COL_COUNT = 300; >> // private static final int COL_COUNT = 200; >> // private static final int COL_COUNT = 100; >> >> public static void main(final String[] args) { >> Application.launch(args); >> } >> >> @Override >> public void start(final Stage stage) { >> final TreeItem<String> root = new TreeItem<>("Root"); >> final TreeTableView<String> treeTableView = new >> TreeTableView<>(root); >> if (USE_HEIGHT_FIXED_SIZE) { >> treeTableView.setFixedCellSize(24); >> } >> treeTableView.setPrefWidth(800); >> treeTableView.setPrefHeight(500); >> stage.setWidth(800); >> stage.setHeight(500); >> >> Platform.runLater(() -> { >> for (int i = 0; i < 100; i++) { >> TreeItem<String> child = this.addNodes(root); >> child = this.addNodes(child); >> child = this.addNodes(child); >> child = this.addNodes(child); >> } >> }); >> >> final TreeTableColumn<String, String>[] cols = new >> TreeTableColumn[COL_COUNT + 1]; >> final TreeTableColumn<String, String> column = new >> TreeTableColumn<>("Column"); >> column.setPrefWidth(150); >> column.setCellValueFactory( >> (final CellDataFeatures<String, String> p) -> >> new ReadOnlyStringWrapper(p.getValue().getValue())); >> cols[0] = column; >> >> for (int i = 0; i < COL_COUNT; i++) { >> final TreeTableColumn<String, String> col = new >> TreeTableColumn<>(Integer.toString(i)); >> col.setPrefWidth(60); >> col.setCellValueFactory(val -> new >> ReadOnlyStringWrapper(val.getValue().getValue()+":"+val.getTreeTableColumn().getText())); >> cols[i + 1] = col; >> } >> treeTableView.getColumns().addAll(cols); >> >> final Scene scene = new Scene(treeTableView, 800, 500); >> stage.setScene(scene); >> stage.show(); >> this.prepareTimeline(scene); >> } >> >> private TreeItem<String> addNodes(final TreeItem<String> parent) { >> >> final TreeItem<String>[] childNodes = new TreeItem[20]; >> for (int i = 0; i < childNodes.length; i++) { >> childNodes[i] = new TreeItem<>("N" + i); >> } >> final TreeItem<String> root = new TreeItem<>("dir"); >> root.setExpanded(true); >> root.getChildren().addAll(childNodes); >> parent.setExpanded(true); >> parent.getChildren().add(root); >> return root; >> } >> >> private void prepareTimeline(final Scene scene) { >> new AnimationTimer() { >> @Override >> public void handle(final long now) { >> final double fps = >> com.sun.javafx.perf.PerformanceTracker.getSceneTracker(scene).getInstantFPS(); >> ((Stage) scene.getWindow()).setTitle("FPS:" + >> (int) fps); >> } >> }.start(); >> } >> >> } > > Column virtualization causes shortness of breath when scrolling a large > stroke horizontally. > This does not happen when stroking on the scrollbar. Looks like a potential > problem with VirtualFlow. > > If you are worried about shortness of breath, the following code will help > reduce the problem. > > > ``` Java >  private static final int OVERLAP_MARGIN = 500; > > private static boolean isOverlap(double start, double end, double start2, > double end2){ > start = Math.max(start-OVERLAP_MARGIN, start2); > end = Math.min(end+OVERLAP_MARGIN, end2); > return (start<=end2 && end >= start2); > } @yososs Per [this message](https://mail.openjdk.java.net/pipermail/openjfx-dev/2020-September/027534.html) on the openjfx-dev mailing list, I have closed [JDK-8185886](https://bugs.openjdk.java.net/browse/JDK-8185886) as a duplicate, and suggested another existing JBS issue for this PR to use. Please change the title to: 8185887: TableRowSkinBase fails to correctly virtualize cells in horizontal direction ------------- PR: https://git.openjdk.java.net/jfx/pull/125