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

Reply via email to