希望大家都过得很好。
我的问题很基本:如果可能,如何隐藏TreeView根部的箭头?在Windows Event Viewer中可以看到我想要实现的一个很好的例子。
我的javafx应用程序如下图所示
默认情况下,车辆旁边的箭头存在。
我阅读了文档here,但只找到了.showRoot(),它无法实现我想要的功能。我真的很感激任何输入,即使这是一种作弊的方式(使用x-offset属性也让我望而却步。)
答案 0 :(得分:3)
箭头是TreeCell
的{{3}}的一部分。未指定时,TreeCell
的皮肤有责任提供默认的公开节点(例如三角形)。这由财产设定者文档说明:
用作“公开”三角形或切换的节点,用于展开和折叠项目。仅在树中包含子项的项时使用。如果未指定,则TreeCell的Skin实现负责提供默认的公开节点。
但看着TreeCellSkin
似乎没有提供默认的公开节点。相反,这似乎由TreeViewSkin
处理(在JavaFX 8和JavaFX 11中)。看一下实现,默认的公开节点是一个StackPane
,其子StackPane
用作实际的箭头。他们的风格类别分别是tree-disclosure-node
和arrow
。请注意,此文件并未出现在任何地方,包括disclosureNode
。
在我看来,隐藏根公开节点的最简单,最不易出错的方法是使用CSS。这里唯一的问题是TreeCell
无法仅将根单元作为目标。但这仍然可以通过子类TreeCell
并提供我们自己的JavaFX CSS Reference Guide来实现。然后,在TreeView
上设置PseudoClass
。
要设置根的图形,请设置根TreeItem
的{{3}}属性。
CustomTreeCell
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";
}
一些注意事项:
TreeCell.graphic
属性绑定到TreeItem.graphic
属性以来,您将无法从CSS设置图形。您可以修改此设置以仅设置图形而不是绑定,以启用该功能。这样,您就不必通过代码设置根TreeItem
的图形,而可以执行.custom-tree-cell:root { -fx-graphic: ...; }
。 答案 1 :(得分:1)
MyTreeCellSkin.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);
}
}
CustomTreeCell.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());
}
}
}
main.java
treeView.setCellFactory(param -> {
CustomTreeCell<String> treeCell = new CustomTreeCell<>();
treeCell.setSkin(new MyTreeCellSkin<>(treeCell));
return treeCell;
});