![](/img/trans.png)
[英]javafx 8: How to update TreeCell in TreeView on SlectedItemProperty Change
[英]How to disable or modify padding of TreeCell in TreeView
環境:JDK 7u75、Windows 8.1 x64、JavaFX2.2
示例代碼:
public class TreeViewSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws MalformedURLException {
primaryStage.setTitle("Tree View Sample");
TreeItem<String> rootItem = new TreeItem<String>("RootNode");
for (int i = 1; i < 5; i++) {
TreeItem<String> item = new TreeItem<String>("SubNode" + i);
rootItem.getChildren().add(item);
item.getChildren().add(new TreeItem<String>("SubSubNode" + i + "" + i));
}
rootItem.getChildren().add(new TreeItem<String>("SecondRootNode"));
TreeView<String> tree = new TreeView<String>(rootItem);
StackPane root = new StackPane();
root.getChildren().add(tree);
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().add((new File("../css/styletest.css").toURI()).toURL().toString());
primaryStage.setScene(scene);
primaryStage.show();
}
}
CSS:
.tree-cell {
-fx-skin: "com.sun.javafx.scene.control.skin.TreeCellSkin";
-fx-background-color: -fx-control-inner-background;
-fx-padding: 0.25em; /* 3 */
-fx-text-fill: -fx-text-inner-color;
-fx-indent: 10;
}
.tree-cell .label {
-fx-padding: 0.0em 0.0em 0.0em 0.25em; /* 0 0 0 3 */
}
.tree-cell .tree-disclosure-node {
-fx-padding: 4 2 4 8;
-fx-background-color: transparent;
}
.tree-cell .tree-disclosure-node .arrow {
-fx-background-color: -fx-mark-color;
-fx-padding: 0.333333em; /* 4 */
-fx-shape: "M 0 -4 L 8 0 L 0 4 z";
}
我們需要刪除所有節點的所有空間和箭頭。 修改后的 CSS:
.tree-cell {
-fx-skin: "com.sun.javafx.scene.control.skin.TreeCellSkin";
-fx-background-color: -fx-control-inner-background;
-fx-padding: 0px;
-fx-text-fill: -fx-text-inner-color;
-fx-indent: 0px;
}
.tree-cell .label {
-fx-padding: 0.0em 0.0em 0.0em 0.0em;
}
.tree-cell .tree-disclosure-node {
-fx-padding: 0px;
-fx-background-color: transparent;
}
.tree-cell .tree-disclosure-node .arrow {
-fx-background-color: -fx-mark-color;
-fx-padding: 0.0em;
}
如您所見,除葉子之外的所有節點都沒有填充和縮進。
問題 - 如何刪除\\修改此填充?
在這種情況下,JavaFX 開發人員將標准長度設為 18,並沒有提供更改它的機會。 這是他們的評論:
/*
* This is rather hacky - but it is a quick workaround to resolve the
* issue that we don't know maximum width of a disclosure node for a given
* TreeView. If we don't know the maximum width, we have no way to ensure
* consistent indentation for a given TreeView.
*
* To work around this, we create a single WeakHashMap to store a max
* disclosureNode width per TreeView. We use WeakHashMap to help prevent
* any memory leaks.
*
* RT-19656 identifies a related issue, which is that we may not provide
* indentation to any TreeItems because we have not yet encountered a cell
* which has a disclosureNode. Once we scroll and encounter one, indentation
* happens in a displeasing way.
*/
但如果真的有必要,那么我們使用反射覆蓋 TreeCellSkin 類和 layoutChildren 方法。 但這並不安全:
final double defaultDisclosureWidth = maxDisclosureWidthMap.containsKey(tree) ?
maxDisclosureWidthMap.get(tree) : 18; // RT-19656: default width of default disclosure node
在
final double defaultDisclosureWidth = 0;
全班:
public class CustomTreeCellSkin<T> extends TreeCellSkin<T> {
public CustomTreeCellSkin(TreeCell control) {
super(control);
}
private boolean disclosureNodeDirty = true;
@Override
protected void layoutChildren(double x, double y, double w, double h) {
try {
TreeView<T> tree = getSkinnable().getTreeView();
if (tree == null) return;
if (disclosureNodeDirty) {
Method method =TreeCellSkin.class.getDeclaredMethod("updateDisclosureNode");
method.setAccessible(true);
method.invoke(this);
disclosureNodeDirty=false;
}
Node disclosureNode = getSkinnable().getDisclosureNode();
TreeItem<?> treeItem = getSkinnable().getTreeItem();
int level = tree.getTreeItemLevel(treeItem);
if (!tree.isShowRoot()) level--;
double leftMargin = getIndent() * level;
x += leftMargin;
// position the disclosure node so that it is at the proper indent
boolean disclosureVisible = disclosureNode != null && treeItem != null && !treeItem.isLeaf();
Field field = TreeCellSkin.class.getDeclaredField("maxDisclosureWidthMap");
field.setAccessible(true);
Map<TreeView<?>, Double> maxDisclosureWidthMap = (Map<TreeView<?>, Double>) field.get(this);
final double defaultDisclosureWidth = 0; // RT-19656: default width of default disclosure node
double disclosureWidth = defaultDisclosureWidth;
if (disclosureVisible) {
if (disclosureNode == null || disclosureNode.getScene() == null) {
updateChildren();
}
if (disclosureNode != null) {
disclosureWidth = disclosureNode.prefWidth(h);
if (disclosureWidth > defaultDisclosureWidth) {
maxDisclosureWidthMap.put(tree, disclosureWidth);
}
double ph = disclosureNode.prefHeight(disclosureWidth);
disclosureNode.resize(disclosureWidth, ph);
positionInArea(disclosureNode, x, y,
disclosureWidth, ph, /*baseline ignored*/0,
HPos.CENTER, VPos.CENTER);
}
}
// determine starting point of the graphic or cell node, and the
// remaining width available to them
final int padding = treeItem != null && treeItem.getGraphic() == null ? 0 : 3;
x += disclosureWidth + padding;
w -= (leftMargin + disclosureWidth + padding);
// Rather ugly fix for RT-38519, where graphics are disappearing in
// certain circumstances
Node graphic = getSkinnable().getGraphic();
if (graphic != null && !getChildren().contains(graphic)) {
getChildren().add(graphic);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
layoutLabelInArea(x, y, w, h);
}
}
在這種情況下的 css 中,您需要指定我們的重寫類:
.tree-cell {
-fx-skin: "CustomTreeCellSkin";
-fx-background-color: -fx-control-inner-background;
-fx-padding: 0px;
-fx-text-fill: -fx-text-inner-color;
-fx-indent: 0px;
}
.tree-cell .label {
-fx-padding: 0.0em 0.0em 0.0em 0.0em;
}
.tree-cell .tree-disclosure-node {
-fx-padding: 0px;
-fx-background-color: transparent;
}
.tree-cell .tree-disclosure-node .arrow {
-fx-background-color: -fx-mark-color;
-fx-padding: 0.0em;
}
對不起我的英語不好。 =)
雖然我真的很欣賞上述解決方案,但它太復雜了,尤其是因為它使用反射並且必須明確允許使用 JPMS 反射。
由於defaultDisclosureWidth
回退值是硬編碼的,我們可以通過填充來否定它。
public static class CustomTreeCell extends TreeCell<Foo> {
static final PseudoClass LEAF = PseudoClass.getPseudoClass("leaf");
@Override
protected void updateItem(Foo item, boolean empty) {
super.updateItem(item, empty);
// ...
pseudoClassStateChanged(LEAF, getTreeItem().isLeaf());
}
}
.tree-cell {
-fx-background-insets: 0;
-fx-padding: 0;
-fx-indent: 0;
}
.tree-cell:leaf {
-fx-padding: 0 0 0 -18px;
}
.tree-cell .tree-disclosure-node,
.tree-cell .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;
}
使用-fx-indent
屬性設置您想要的任何填充。
簡單驗證:
TreeItem<Foo> nodeRoot = new TreeItem<>(new Foo("root"));
TreeItem<Foo> nodeTest1 = new TreeItem<>(new Foo("test1"));
nodeRoot.getChildren().add(nodeTest1);
TreeItem<Foo> nodeTest2 = new TreeItem<>(new Foo("test2"));
nodeTest1.getChildren().add(nodeTest2);
TreeItem<Foo> nodeTest3 = new TreeItem<>(new Foo("test3"));
nodeTest2.getChildren().add(nodeTest3);
TreeItem<Foo> nodeTest4 = new TreeItem<>(new Foo("test4"));
nodeTest3.getChildren().add(nodeTest4);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.