簡體   English   中英

如何在 TreeView 中禁用或修改 TreeCell 的填充

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM