如何在JavaFX 8中为复杂的TreeView <t>定义一个简单的模型?

时间:2015-06-21 11:28:29

标签: java treeview javafx-8

  

TLDR :如何在TreeItem中实施JavaFX 8 TreeView   不同的对象类型?

我的XML配置具有以下对象结构。

[Configuration] --- has 1-n ---> [Group] --- has 1-n ---> [Topic]

我想在TreeView中显示此结构,如下所示。

Groups
|
+-- Group A
|    |-- Topic A
|    |-- Topic B
|
+-- Group B
     |-- Topic C
     |-- Topic D

在阅读TreeItem文档后,我无法想到解决方案,因为我的结构中的对象类型不同,因此我无法定义{{1}与TreeItem的示例中的TreeItem<T>类似。

我想知道如何为上述结构定义一个精心设计的模型,以满足以下要求。

  • 根据叶子的类类型显示不同的上下文菜单
  • 在树的任何级别插入和删除叶子的可能性
  • 轻松访问叶子对象,以便我可以在其上调用getter / setter
  • 模型更改时
  • 树自动更新

现有解决方案的任何解决方案或好文章?

1 个答案:

答案 0 :(得分:2)

所以@kleopatra(非常感谢)指出我使用类型<Object>我做了如下。

public class TreeController implements Initializable {

    ...

    @FXML
    private TreeView<Object> treeView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        TreeItem<Object> root = new TreeItem<>("Groups");

        for (Object object : cfg.getGroupList()) {
            root.getChildren().add(createNode(object));
        }

        treeView.setRoot(root);
        treeView.setCellFactory(p -> new TreeCellFactory());

        root.setExpanded(true);
    }

    private TreeItem<Object> createNode(Object o) {
        return new TreeItem<Object>(o) {
            private boolean isLeaf;
            private boolean isFirstTimeChildren = true;
            private boolean isFirstTimeLeaf = true;

            @Override
            public ObservableList<TreeItem<Object>> getChildren() {
                if (isFirstTimeChildren) {
                    isFirstTimeChildren = false;

                    super.getChildren().setAll(buildChildren(this));
                }
                return super.getChildren();
            }

            @Override
            public boolean isLeaf() {
                if (isFirstTimeLeaf) {
                    isFirstTimeLeaf = false;

                    if (o instanceof Topic) {
                        isLeaf = true;
                    }
                }

                return isLeaf;
            }

            private ObservableList<TreeItem<Object>> buildChildren(TreeItem<Object> treeItem) {
                if (treeItem.getValue() instanceof Group) {
                    ObservableList<TreeItem<Object>> children = FXCollections.observableArrayList();

                    for (Object object : ((Group) treeItem.getValue()).getTopicList()) {
                        children.add(createNode(object));
                    }

                    return children;
                }

                return FXCollections.emptyObservableList();
            }
        };
    }

    private final class TreeCellFactory extends TreeCell<Object> {
        private ContextMenu topicMenu = new ContextMenu();
        private ContextMenu groupMenu = new ContextMenu();

        public TreeCellFactory() {
            MenuItem topicMenuItem = new MenuItem("- Item 1 -");
            topicMenu.getItems().add(topicMenuItem);

            MenuItem groupMenuItem = new MenuItem("- Item 1 -");
            groupMenu.getItems().add(groupMenuItem);
        }

        @Override
        public void updateItem(Object item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
            } else {
                setText(item.toString());
            }

            if (item instanceof Topic) {
                setContextMenu(topicMenu);
            }

            if (item instanceof Group) {
                setContextMenu(groupMenu);
            }
        }


    }
}

请注意,我会将toString()Topic中的Group覆盖到我希望在树叶上显示的文字。