On Mon, 24 Feb 2020 07:39:43 GMT, yosbits <d...@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(); > } > > }
This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/jfx/pull/125