TreeView 的占位符?

Placeholder for TreeView?

我有一个开始时为空的 TreeView,我想设置一个占位符直到它为空。就像可用于 ListView 的那个 (setPlaceholder())

我的第一个想法是将 TreeView 包装到 BorderPane 中,然后根据 TreeView 中元素的数量更改中心。问题是虽然我通过拖放将元素添加到 TreeView,并且如果我将标签设置到中心以替换占位符,我将无法再将我的项目拖放到 TreeView 中。任何建议将不胜感激。

TreeView 不支持占位符 - 不完全确定,为什么不,但可能是空树(不管这意味着什么:空根?没有 children 的根?根不显示?)是一种稀有物种.

不过,通过遵循支持它的虚拟化控件 f.i 的实现,实现起来相当简单。表视图。我们只需要一个自定义的 TreeViewSkin

  • 管理(根据需要创建并添加到树的层次结构和布局)占位符
  • 监听树的相关状态并适当更新占位符的可见性

一个例子,通过按钮在 null/not null 之间切换树的根来切换空:

public class TreeViewWithPlaceholder extends Application {


    private static class TreeViewPlaceholderSkin<T> extends TreeViewSkin<T> {

        private StackPane placeholderRegion;
        private Label placeholderLabel;

        public TreeViewPlaceholderSkin(TreeView<T> control) {
            super(control);
            installPlaceholderSupport();
        }

        private void installPlaceholderSupport() {
            registerChangeListener(getSkinnable().rootProperty(), e -> updatePlaceholderSupport());
            updatePlaceholderSupport();
        }

        /**
         * Updating placeholder/flow visibilty depending on whether or not the tree
         * is considered empty. 
         * 
         * Basically copied from TableViewSkinBase.
         */
        private void updatePlaceholderSupport() {
            if (isTreeEmpty()) {
                if (placeholderRegion == null) {
                    placeholderRegion = new StackPane();
                    placeholderRegion.getStyleClass().setAll("placeholder");
                    getChildren().add(placeholderRegion);

                    placeholderLabel = new Label("No treeItems");
                    placeholderRegion.getChildren().setAll(placeholderLabel);
                }
            }
            getVirtualFlow().setVisible(!isTreeEmpty());
            if (placeholderRegion != null)
                placeholderRegion.setVisible(isTreeEmpty());
        }


        @Override
        protected void layoutChildren(double x, double y, double w, double h) {
            super.layoutChildren(x, y, w, h);
            if (placeholderRegion != null && placeholderRegion.isVisible()) {
                placeholderRegion.resizeRelocate(x, y, w, h);
            }
        }

        private boolean isTreeEmpty() {
            return getSkinnable().getRoot() == null;
        }

    }

    private Parent createContent() {
        TreeView<String> tree = new TreeView<>() {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new TreeViewPlaceholderSkin<>(this);
            }

        };

        Button toggle = new Button("toggleRoot");
        toggle.setOnAction(e -> {
            TreeItem<String> root = tree.getRoot();
            tree.setRoot(root == null ? new TreeItem<>("root") : null);
        });
        BorderPane content = new BorderPane(tree);
        content.setBottom(toggle);
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        //stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(TreeViewWithPlaceholder.class.getName());

}