且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-09-11 23:03:16

在JavaFX中,当正在处理对该列表的现有更改时,不允许更改ObservableList. (无论这是否是明智的规则,都有待商debate,但这是一条规则.)

In JavaFX, you are not allowed to change an ObservableList while an existing change to that list is being processed. (Whether or not this is a sensible rule is open to debate, nevertheless, it is a rule.)

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

The selection model keeps ObservableLists of both the selected indices and the selected items. Part of the processing of changes in those lists is to call listeners on the selected item and selected index. Consequently, you can't change the selection from a listener on the selection itself.

执行此操作的正确"方法是提供您自己的选择模型实现.这有点痛苦,因为有很多方法要实现,而且它们的使用没有充分的文档记录.这是一个示例,尽管这只是一个起点,而不是为了提高产品质量:

The "proper" way to do this would be to provide your own implementation of the selection model. This is a bit of a pain, as there are a lot of methods to implement, and their use is not well documented. Here is an example, though this is intended as a starting point and is not intended to be production quality:

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