选择父级时,JavaFX TreeTable选择子级并从父级中删除选择

时间:2015-11-11 16:55:05

标签: javafx-8 treetableview

我有一个最大深度为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);
    }
  }
});

启用多选模式。

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:2)

在JavaFX中,在处理对该列表的现有更改时,不允许更改ObservableList。 (这是否是一个明智的规则是开放的辩论,然而,这是一个规则。)

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

&#34;适当&#34;这样做的方法是提供自己的选择模型实现。这有点痛苦,因为有很多方法要实现,并且它们的使用没有很好地记录。这是一个例子,虽然这是一个起点,并不打算成为生产质量:

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);
    }
}