javafx:如何隐藏TreeView中的“下拉箭头”?

y1aodyip  于 2023-01-04  发布在  Java
关注(0)|答案(3)|浏览(344)

希望大家都过得好。
我的问题很简单:如果可能,如何隐藏TreeView根部的箭头?Windows事件查看器中有一个很好的示例,说明了我希望实现的目标。

虽然我的javafx应用程序看起来像下面的图像

默认情况下,车辆旁边会显示该箭头。
我阅读了here文档,但我只找到了. showRoot(),它没有达到我想要的效果。我真的很感激任何输入,即使这是一种欺骗性的方法(使用x-offset属性出现在我的脑海中)。

f45qwnt8

f45qwnt81#

箭头是TreeCelldisclosureNode的一部分。如果未指定,则TreeCell的外观负责提供默认的显示节点(例如三角形)。属性设置程序文档对此进行了说明:
要用作“显示”三角形或切换的节点,用于展开和折叠项。这仅在树中的项包含子项的情况下使用。如果未指定,TreeCell的外观实现将负责提供默认显示节点。
然而,看看TreeCellSkin,它似乎 * 没有 * 提供默认的公开节点,相反,这似乎是由TreeViewSkin处理的(在JavaFX 8和JavaFX 11中都有)。看一下这个实现,默认的显示节点是一个StackPane,它有一个作为实际箭头的子节点StackPane。它们的样式类是tree-disclosure-nodearrow。请注意,这在任何地方都没有文档记录,包括JavaFX CSS Reference Guide
在我看来,隐藏根公开节点最简单、最不容易出错的方法是使用CSS。这里唯一的问题是TreeCell没有提供只针对根单元格的方法。但这仍然可以通过将TreeCell子类化并提供我们自己的PseudoClass来实现。然后我们在TreeView上设置cellFactory
要设置根的图形,请设置根TreeItemTreeItem.graphic属性。

自定义树单元格

import javafx.beans.InvalidationListener;
import javafx.css.PseudoClass;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.util.Callback;

public class CustomTreeCell<T> extends TreeCell<T> {

    private static final PseudoClass ROOT = PseudoClass.getPseudoClass("root");

    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView() {
        return treeView -> new CustomTreeCell<>();
    }

    public CustomTreeCell() {
        getStyleClass().add("custom-tree-cell");

        InvalidationListener listener = observable -> {
            boolean isRoot = getTreeView() != null && getTreeItem() == getTreeView().getRoot();
            pseudoClassStateChanged(ROOT, isRoot);
        };

        treeViewProperty().addListener(listener);
        treeItemProperty().addListener(listener);
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            graphicProperty().unbind();
            setGraphic(null);
        } else {
            setText(item.toString()); // Really only works if item is a String. Change as needed.
            graphicProperty().bind(getTreeItem().graphicProperty());
        }
    }

}

CSS文件

.custom-tree-cell:root .tree-disclosure-node,
.custom-tree-cell:root .arrow {

    -fx-min-width: 0;
    -fx-pref-width: 0;
    -fx-max-width: 0;

    -fx-min-height: 0;
    -fx-pref-height: 0;
    -fx-max-height: 0;

}

/* Related to question asked in the comments by OP */
.custom-tree-cell > .tree-disclosure-node > .arrow {
    -fx-shape: "M 0 0 L 10 5 L 0 10 L 0 8 L 8 5 L 0 2 Z";
}
  • 注意事项:*

1.* 因为我在单元格实现中将TreeCell.graphic属性绑定到TreeItem.graphic属性,所以您将无法从CSS设置图形。您可以修改此属性,以简单地设置图形,而不是绑定,从而启用该功能。这样您就不必通过代码设置根TreeItem的图形,而是可以设置.custom-tree-cell:root { -fx-graphic: ...; }。*
1.* 这不会移除显示节点,只是使其没有宽度和高度。*
1.* 此解决方案依赖于实施细节;更改JavaFX版本时要小心。我只在JavaFX 11. 0. 2上尝试过,但我相信它也应该适用于JavaFX 8。*

4jb9z9bj

4jb9z9bj2#

我的树细胞皮肤.java

import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.control.skin.TreeCellSkin;

public class MyTreeCellSkin<T> extends TreeCellSkin<T> {

    public MyTreeCellSkin(TreeCell<T> control) {
        super(control);
    }

    @Override
    protected void layoutChildren(double x, double y, double w, double h) {
        super.layoutChildren(x, y, w, h);

        TreeView<T> tree = getSkinnable().getTreeView();

        int level = tree.getTreeItemLevel(getSkinnable().getTreeItem());
        if (!tree.isShowRoot()) {
            level--;
        }
        double leftMargin = getIndent() * level;

        x += leftMargin;

        double disclosureWidth = 18;

        final int padding = 3;
        // x += disclosureWidth + padding;
        x += 3;

        w -= (leftMargin + disclosureWidth + padding);

        layoutLabelInArea(x, y, w, h);
    }
}

自定义树单元格.java

import javafx.beans.InvalidationListener;
import javafx.css.PseudoClass;
import javafx.scene.control.TreeCell;

public class CustomTreeCell<T> extends TreeCell<T> {

    private static final PseudoClass ROOT = PseudoClass.getPseudoClass("root");

    public CustomTreeCell() {
        getStyleClass().add("custom-tree-cell");

        InvalidationListener listener = observable -> {
            boolean isRoot = getTreeView() != null && getTreeItem() == getTreeView().getRoot();
            pseudoClassStateChanged(ROOT, isRoot);
        };

        treeViewProperty().addListener(listener);
        treeItemProperty().addListener(listener);
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            graphicProperty().unbind();
            setGraphic(null);
        } else {
            setText(item.toString());
            graphicProperty().bind(getTreeItem().graphicProperty());
        }
    }

}

主要.java

treeView.setCellFactory(param -> {
           CustomTreeCell<String> treeCell = new CustomTreeCell<>();
           treeCell.setSkin(new MyTreeCellSkin<>(treeCell));
           return treeCell;
});
r7s23pms

r7s23pms3#

在JavaFX8中,您所需要的只是更新扩展TreeCell中的两个样式类。

在我的TreeCell构造函数中,我使用了StackPane作为图形,并设置了带有反向填充值的样式。

stackPane.setStyle("-fx-padding: 0 0 0 -5;");
        
// update styles in updateItem method

    @Override
    public void updateItem(Group item, boolean empty) {
    super.updateItem(item, empty);
    setText(null);
    setGraphic(null);
    getStyleClass().remove("just-core-tree-cell");
    getStyleClass().remove("core-leaf-tree-cell");
            
    if (empty || null == item) {
      return;
    }

// i coded a simple method to check if parent item is the root item
// but you can do same with a getTreeItem() parent check instead

    boolean isCoreGroup = item.isParentRoot();
    boolean isLeaf = item.isLeaf();

    if (isCoreGroup && isLeaf) {
                getStyleClass().add("core-leaf-tree-cell");
            }
    
    if (isCoreGroup && !isLeaf) {
                getStyleClass().add("just-core-tree-cell");
            }

 // Do some other graphical updates on the stack pane...
    setGraphic(this.stackPane);
 // Set different icon depending on the TreeItem's expanded state as indicator
    getTreeItem().setGraphic(iconExpanded);

在CSS样式文件中按如下方式设置填充值

.tree-cell {
                -fx-indent: 8.0;
                -fx-padding: 0.0 2.0 0.0 -10.0;
            }
            
            /* (leafs) indent compensation to the left space*/
            .core-leaf-tree-cell {
/* because +18 is the hard coded left space padding, BUG: JDKJDK-8180646
 * TreeView renders TreeCells with superfluous indentation if disclosure 
 * node is not visible or smaller than 18px in width */
                -fx-padding: 0 2px 0 -21px;
            }
            
            .just-core-tree-cell{
                -fx-padding: 0 2px 0 3px;
            }
            
            .just-core-tree-cell .tree-disclosure-node, .just-core-tree-cell .arrow, .just-core-tree-cell:expanded .tree-disclosure-node .arrow
                {
                -fx-rotate: 0;
                -fx-scale-shape: true;
                -fx-min-width: 0;
                -fx-pref-width: 0;
                -fx-max-width: 0;
                -fx-min-height: 0;
                -fx-pref-height: 0;
                -fx-max-height: 0;
            }

相关问题