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

How to define a simple model for a complex TreeView<T> in JavaFX 8?

TLDR: How to implement JavaFX 8 TreeItem in a TreeView with different object types?

我有 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 documentation I just can't think of a solution because the objects in my structure are not of the same type and so I can't just define a TreeItem<T> with TreeItem<File> like in the example at TreeItem.

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

有没有解决方案或者有好的文章有现成的解决方案?

所以在@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);
            }
        }


    }
}

请注意,我将 TopicGroup 中的 toString() 覆盖为我希望出现在树叶上的文本。