行数较大时 JavaFX TableView 滚动性能问题

and*_*bot 7 java javafx tableview

我很困惑。我有一个用例,涉及以 TableView 形式呈现任意大的分页表格结果集。

我发现,当我滚动到较大的行序数时,精细滚动(通过 TableView 上的触摸手势或鼠标滚轮)和粗滚动(通过拖动滚动条滑块)都会降低到无法使用。

降级发生在相对较小的行数(<~1M)时。请注意,数据模型仅在任何给定的行偏移处保存一小部分数据,并动态加载页面以响应滚动事件。

我将用例提炼为下面的几行代码。我过去能够支持类似的用例(大约 4 年前,10 亿行),没有任何问题,所以我知道这是可行的。然而,无论现在的问题是什么,我就是看不到它。

迫切需要帮助...

顺便说一句,我已经尝试过使用 SDK 和 JavaFX 的各种排列来实现相同的效果。

package com.example.demo;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableListBase;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class Main extends Application {

    public static void main(String[] args) {
        launch();
    }

    @Override
    public void start(Stage stage) {
        final TableView<Row> table = new TableView();
        final BorderPane borderPane = new BorderPane();
        final Scene scene = new Scene(borderPane, 800, 600);

        TableColumn<Row, String> col = new TableColumn<>("row");
        col.setCellValueFactory(p -> new SimpleStringProperty(p.getValue().data[0].toString()));
        col.setPrefWidth(100);
        table.getColumns().add(col);

        col = new TableColumn<>("A");
        col.setCellValueFactory(p -> new SimpleStringProperty(p.getValue().data[1].toString()));
        col.setPrefWidth(100);
        table.getColumns().add(col);

        col = new TableColumn<>("B");
        col.setCellValueFactory(p -> new SimpleStringProperty(p.getValue().data[2].toString()));
        col.setPrefWidth(100);
        table.getColumns().add(col);

        col = new TableColumn<>("C");
        col.setCellValueFactory(p -> new SimpleStringProperty(p.getValue().data[3].toString()));
        col.setPrefWidth(100);
        table.getColumns().add(col);

        table.setCache(true);
        table.setEditable(false);
        table.setCacheHint(CacheHint.SPEED);

        table.setItems(getModel(10_000_000));

        borderPane.setCenter(table);
        stage.setScene(scene);

        stage.show();
    }

    private static ObservableList<Row> getModel(final int rowCount) {
        final List<Row> data = new ArrayList<>(rowCount);
        for (int x = 0; x < rowCount; x++) {
            data.add(new Row(x, new Object[] {x, "a_" + x, "b_" + x, "c_" + x }));
        }
        return FXCollections.unmodifiableObservableList(FXCollections.observableList(data));
    }

    private static final class Row {
        public final int rowOrdinal;
        public final Object[] data;

        public Row(final int rowOrdinal, final Object[] data) {
            this.rowOrdinal = rowOrdinal;
            this.data = data;
        }

        @Override
        public boolean equals(Object o) {
            return o != null && o.getClass() == Row.class && ((Row)o).rowOrdinal == rowOrdinal;
        }
        
        @Override
        public int hashCode() {
            return rowOrdinal;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

jew*_*sea 7

是否出现了性能下降?

是的。

我在 OpenJDK 20 + JavaFX 20 OS X x64 13.2.1、2020 MacBook Pro 上运行了示例。对于大量行(例如 1,000,000+),通过滚动条使用鼠标滚动时性能会很慢。当有 1,000 行时,滚动性能很好。

使用 OpenJDK 8b251,滚动 10,000,000 行的性能很快。

正如Maatr指出的那样,这看起来是一个已知问题:

如果您认为您的问题是一个不同的问题,您可以考虑提交错误报告

解决方法

使用 8 到 17 之间的 JavaFX 版本。从我的本地测试来看,具有大数据集的 TableView 的滚动性能可以接受。

对于其他 JavaFX 版本,您可以搜索在大型数据集支持时提高 TableView 性能的解决方法,但我不建议您这样做,除非您熟练且有动力这样做。相反,如果需要出现此性能问题的 JavaFX 版本,请重新设计您的 UI 和逻辑,以便您不会将大量项目加载到TableView支持列表中。也许,将最大项目数限制为 10,000 左右,并通过分页处理大量数据。

知道这是什么时候开始的吗?

大型数据集的主要 TableView 滚动性能问题始于 JavaFX 版本 18。

对于我提到的 JDK 8b251 版本,1,000 行或 10,000,000 行的滚动性能是相同的(优秀)。

对于 JavaFX 17.0.2 版本(在 OS X x64 13.2.1、OpenJDK 20 上),10,000,000 行的滚动性能会稍微有些卡顿,但总体来说还不错。性能比 1,000 行的良好性能稍差,但并不是真正的问题。

对于 JavaFX 18.0.2、19.0.2.1 和 20 版本(在 OS X x64 13.2.1、OpenJDK 20 上),10,000,000 行的滚动性能将严重卡顿。性能比 1,000 行的良好性能差很多。

这些结果来自我的环境中本地测试的主观视觉观察。您在自己的环境中进行测试的结果和主观观察结果可能会有所不同,但可能大体相似。

  • 知道这是什么时候开始的吗? (2认同)