JavaFX:TreeView selectedItems 的 bindContent

JavaFX: bindContent of TreeView selectedItems

我想绑定 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 个项目。 Select 在树中查看从 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
-------------------

您可以看到 "removed at 6" 然后是 "removed at 7",但是基础列表的大小也发生了变化,因此不应在此处增加索引,即所有 "removed at" 都应为 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()));
            }
        });