这似乎是一个简单的问题,但我自己无法找到解决方案。
我有一个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中的大量行?
答案 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代码的一部分......