1

我有一个最大深度为 2 的 TreeTable,例如

  • fooType

    -foo

    -foo

如果我选择 fooType 我希望程序自动选择所有子项并取消选择父项。但是当我尝试这个时,我总是得到一个 IndexOutOfBoundsException。

myTreeTable.getSelectionModel().selectedItemProperty().addListener((obs, ov, nv) -> {
  if (nv.getValue() instanceof fooType) {
    myTreeTable.getSelectionModel().clearSelection(myTreeTable.getSelectionModel().getSelectedIndex());
    if (!nv.isExpanded()) {
      nv.setExpanded(true);
    }
    ObservableList<TreeItem<IfooTreeItem>> children = nv.getChildren();
    for (TreeItem<IfooTreeItem> item : children) {
      annotationsTreeTable.getSelectionModel().select(item);
    }
  }
});

启用多选模式。

任何帮助表示赞赏。

4

1 回答 1

2

在 JavaFX 中,不允许ObservableList在处理对该列表的现有更改时进行更改。(这是否是一个明智的规则还有待商榷,然而,它是一个规则。)

选择模型保留ObservableList所选索引和所选项目的 s。这些列表中更改的部分处理是调用所选项目和所选索引的侦听器。因此,您不能从选择本身的侦听器更改选择。

执行此操作的“正确”方法是提供您自己的选择模型实现。这有点痛苦,因为有很多方法可以实现,而且它们的使用没有很好的文档记录。这是一个示例,尽管这只是一个起点,而不是生产质量:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TreeSelectionExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        TreeView<String> tree = new TreeView<>();
        TreeItem<String> root = new TreeItem<>();
        tree.setRoot(root);
        tree.setShowRoot(false);

        root.getChildren().add(new TreeItem<>("Item 1"));
        root.getChildren().add(new TreeItem<>("Item 2"));

        root.getChildren().forEach(item -> 
            Stream.of("A", "B").map(s -> new TreeItem<String>(item.getValue()+s))
            .forEach(item.getChildren()::add));

        MultipleSelectionModel<TreeItem<String>> defaultSelectionModel = tree.getSelectionModel() ;
        defaultSelectionModel.setSelectionMode(SelectionMode.MULTIPLE);

        tree.setSelectionModel(new MultipleSelectionModel<TreeItem<String>>() {

            {
                setSelectionMode(SelectionMode.MULTIPLE);
            }

            @Override
            public ObservableList<Integer> getSelectedIndices() {
                return defaultSelectionModel.getSelectedIndices();
            }

            @Override
            public ObservableList<TreeItem<String>> getSelectedItems() {
                return defaultSelectionModel.getSelectedItems();
            }

            @Override
            public void selectRange(int start, int end) {
                System.out.println("selectRange("+start+", "+end+")");
                List<TreeItem<String>> items = new ArrayList<>();
                for (int i = start; i < end; i++) {
                    items.add(tree.getTreeItem(i));
                }
                for (int i = start ; i > end; i--) {
                    items.add(tree.getTreeItem(i));
                }
                items.forEach(this::select);
            }

            @Override
            public void selectIndices(int index, int... indices) {
                System.out.println("select("+index+", "+Arrays.toString(indices)+")");
                TreeItem<String> item = tree.getTreeItem(index);
                if (item.isLeaf()) {
                    defaultSelectionModel.select(item);;
                } else {
                    List<TreeItem<String>> leaves = new ArrayList<>();
                    findLeavesAndExpand(item, leaves);
                    for (TreeItem<String> leaf : leaves) {
                        defaultSelectionModel.select(leaf);
                    }
                }
                for (int i : indices) {
                    item = tree.getTreeItem(i);
                    if (item.isLeaf()) {
                        defaultSelectionModel.select(item);;                        
                    } else {
                        List<TreeItem<String>> leaves = new ArrayList<>();
                        findLeavesAndExpand(item, leaves);
                        for (TreeItem<String> leaf : leaves) {
                            defaultSelectionModel.select(leaf);
                        }
                    }
                }
            }

            @Override
            public void selectAll() {
                System.out.println("selectAll()");
                List<TreeItem<String>> leaves = new ArrayList<>();
                findLeavesAndExpand(tree.getRoot(), leaves);
                for (TreeItem<String> leaf : leaves) {
                    defaultSelectionModel.select(leaf);
                }
            }

            @Override
            public void selectFirst() {
                System.out.println("selectFirst()");
                TreeItem<String> firstLeaf ;
                for (firstLeaf = tree.getRoot(); ! firstLeaf.isLeaf(); firstLeaf = firstLeaf.getChildren().get(0)) ;
                defaultSelectionModel.select(firstLeaf);
            }

            @Override
            public void selectLast() {
                System.out.println("selectLast()");
                TreeItem<String> lastLeaf ;
                for (lastLeaf = tree.getRoot(); ! lastLeaf.isLeaf(); 
                        lastLeaf = lastLeaf.getChildren().get(lastLeaf.getChildren().size()-1)) ;
                defaultSelectionModel.select(lastLeaf);
            }

            @Override
            public void clearAndSelect(int index) {
                TreeItem<String> item = tree.getTreeItem(index);
                defaultSelectionModel.clearSelection();
                if (item.isLeaf()) {
                    defaultSelectionModel.select(item);
                } else {
                    List<TreeItem<String>> leaves = new ArrayList<>();
                    findLeavesAndExpand(item, leaves);
                    for (TreeItem<String> leaf : leaves) {
                        defaultSelectionModel.select(leaf);
                    }
                }
            }

            @Override
            public void select(int index) {
                System.out.println("select("+index+")");
                select(tree.getTreeItem(index));
            }

            @Override
            public void select(TreeItem<String> item) {
                System.out.println("select("+item.getValue()+")");
                if (item.isLeaf()) {
                    defaultSelectionModel.select(item);
                } else {
                    List<TreeItem<String>> leaves = new ArrayList<>();
                    findLeavesAndExpand(item, leaves);
                    for (TreeItem<String> leaf : leaves) {
                        defaultSelectionModel.select(leaf);
                    }                    
                }
            }

            @Override
            public void clearSelection(int index) {
                defaultSelectionModel.clearSelection(index);
            }

            @Override
            public void clearSelection() {
                defaultSelectionModel.clearSelection();
            }

            @Override
            public boolean isSelected(int index) {
                return defaultSelectionModel.isSelected(index);
            }

            @Override
            public boolean isEmpty() {
                return defaultSelectionModel.isEmpty();
            }

            @Override
            public void selectPrevious() {
                // TODO Auto-generated method stub
                // not sure on implementation needed here
            }

            @Override
            public void selectNext() {
                System.out.println("selectNext()");
                // TODO Auto-generated method stub
                // not sure on implementation needed here
            }

            private void findLeavesAndExpand(TreeItem<String> node, List<TreeItem<String>> leaves) {
                if (node.isLeaf()) {
                    leaves.add(node);
                } else {
                    node.setExpanded(true);
                    for (TreeItem<String> child : node.getChildren()) {
                        findLeavesAndExpand(child, leaves);
                    }
                }
            }

        });

        primaryStage.setScene(new Scene(new BorderPane(tree), 400, 400));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
于 2015-11-11T18:42:09.110 回答