On Thu, 3 Sep 2020 07:44:55 GMT, yosbits
<[email protected]> 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