JavaFX:绑定 TreeView 选定项的内容



我想绑定TreeView所选项目列表的内容,并在删除元素时遇到所选项目更改值的奇怪行为。我写了一些测试应用程序:

public class TreeViewSelectedItemsBindingTest extends Application {
public class Item extends TreeItem<Integer> {
public Item(Integer... value) {
Arrays.stream(value).forEach(v -> getChildren().add(new TreeItem<Integer>(v)));
}
}
@Override
public void start(Stage primaryStage) throws Exception {
TreeView<Integer> treeView = new TreeView<>();
treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
treeView.setRoot(new Item(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
treeView.getRoot().setExpanded(true);
treeView.setShowRoot(false);
ListView<TreeItem<Integer>> listView = new ListView<>();
Bindings.bindContent(listView.getItems(), treeView.getSelectionModel().getSelectedItems());
treeView.getSelectionModel().getSelectedItems()
.addListener((ListChangeListener<? super TreeItem<Integer>>) change -> {
System.out.println("Change: " + change);
System.out.println("TreeView size: " + treeView.getSelectionModel().getSelectedItems().size());
System.out.println("ListView size: " + listView.getItems().size());
System.out.println("-------------------");
});
HBox box = new HBox();
box.getChildren().addAll(treeView, listView);
primaryStage.setScene(new Scene(box));
primaryStage.show();
}
static public void main(String[] args) {
launch(args);
}
}

此应用程序将TreeView选定项绑定到ListView项。例如,在树视图中选择从 0 到 9 的所有元素,然后按SHIFT+元素 5,将所选内容从 0 更改为 5 个元素。你会得到一个解释:

Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException: toIndex = 9

这是因为 ListChangeListener.change 报告从相对于初始未修改列表的索引,而不是相对于以前更改的列表:

-------------------
Change: { [TreeItem [ value: 6 ]] removed at 6,  }
TreeView size: 9
ListView size: 9
-------------------
Change: { [TreeItem [ value: 7 ]] removed at 7,  }
TreeView size: 8
ListView size: 8
-------------------

您可以看到"在 6 处删除"然后"在 7 处删除",但基础列表的大小也发生了变化,因此不应在此处增加索引,即所有"在 6 处删除"都应为 6。正因为如此,Bindings.bindContent 失败了。

这是一个错误JDK-8180359。作为解决方法,应将保税列表更新为整个:

treeView.getSelectionModel().getSelectedItems().addListener(
(ListChangeListener<? super TreeItem<Model>>) change -> {
while (change.next()) {
listView.setAll(change.getList().stream()
.filter(Objects::nonNull)
.map(i -> i.getValue())
.collect(toList()));
}
});

最新更新