JavaFX:在大表中选择很多行

时间:2014-12-12 13:06:18

标签: javafx tableview

这似乎是一个简单的问题,但我自己无法找到解决方案。

我有一个TableView(坦率地说,我有两个TableViews,并希望将项目从一个放到另一个),其中包含大量行(对于我的测试,我有一点点超过6600)。

当我移动项目时,我想将目标表的选择修改为刚刚选择的目标表。

@FXML
private TableView<PositionWrapper> source;

@FXML
private TableView<PositionWrapper> target;

private ObservableList<PositionWrapper> sourceList = FXCollections.observableArrayList();

private ObservableList<PositionWrapper> targetList = FXCollections.observableArrayList();


private void moveSourceToTarget(MouseEvent event) {
    // collecting selected items
    ObservableList<PositionWrapper> selectedItems = 
        FXCollections.observableArrayList(
            source.getSelectionModel().getSelectedItems());

    // Adding selected items to the target
    targetList.addAll(selectedItems);

    // Removing selected items from source
    sourceList.removeAll(selectedItems);

    // Clearing the selection in both table (source has none of the 
    // selected items now, the target selection should be updated completely)
    target.getSelectionModel().clearSelection();
    source.getSelectionModel().clearSelection();

    // My first try. Doesn't work (UnsupportedOperationException)
    target.getSelectionModel().getSelectedItems().setAll(selectedItems);

    // Second try: doing it one-by-one. Works, but extremely slow.
    selectedItems.stream().forEach(p -> target.getSelectionModel().select(p));
}

第二种选择有效,但速度极慢。 (我不知道多慢,因为我在20秒后杀了我的程序。)

我的问题:如何快速选择TableView中的大量行?

1 个答案:

答案 0 :(得分:0)

我进行了更深入的搜索并检查了MultipleSelectionModelBase类的实现源代码。当按行内容选择项目时(正如我在第二次尝试中所做的那样),它遍历表中的所有项目以查找它的索引,然后使用找到的索引调用select(int)方法。

这意味着按内容选择多行是一种n * m算法,在选择(几乎)所有项目时最差情况为n ^ 2。

但这也给了我解决方案。正如我现在向我证明的那样,只有按值选择会受到n ^ 2异常的影响,自然的解决方法是使用基于索引的选择。

这是我的代码段:

private void moveSourceToTarget(MouseEvent event) {
    [...]

    // Allocating an array to store indexes
    int[] idx = new int[selectedItems.size()];
    int p = 0;
    // Performance tuning to move selected items into a set 
    // (faster contains calls)
    Set<PositionWrapper> s = new HashSet<>(Arrays.asList(
        selectedItems.toArray(new PositionWrapper[0])));

    // Iterating over items in target list (but only once!)
    for (int i = 0; i < target.getItems().size(); i++) {
        if (s.contains(target.getItems().get(i))) {
            // and adding to the list of indexes when selected
            idx[p++] = i;
        }
    }
    // Calling the more effective index-based selection setter
    target.getSelectionModel().selectIndices(-1, idx);
}

后果:选择6600件物品所需的时间从20秒减少到0.1秒。

顺便说一句,我不知道为什么selectAll(S...)不是JavaFX代码的一部分......