[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-openjfx-dev
Subject:    Withdrawn: 8185887: TableRowSkinBase fails to correctly virtualize cells in horizontal direction
From:       duke <duke () openjdk ! org>
Date:       2023-04-29 2:59:53
Message-ID: dI9i9bToCNnsC8rGDMTjCWAegMtZlEddtM26LUgyEfY=.cfd964e5-6040-451e-834a-15233b98174a () github ! com
[Download RAW message or body]

On Mon, 24 Feb 2020 07:39:43 GMT, yosbits <duke@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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic