1

I have defined images for the two states of a disclosure node (collapse/expand) according to Change expand and collapse image TreeView JavaFX 2.2

But I would like to have a third image for folder nodes, which still haven't any children nodes. It should not possible to expand/collapse such nodes, but it should display an image too (i.e. a minus.png for expanded nodes, a plus.png for collapsed nodes and an empty rectangle for folder nodes without any children).

Is it possible?

Community
  • 1
  • 1
witchi
  • 345
  • 3
  • 16

2 Answers2

0

Having no children means that tree item is leaf node with type of "folder". You can utilize graphic property of tree item to show "empty rectangle" image:

ImageView ivfolder = new ImageView( "path/to/empty_rectangle.png" );

// You may use bindings
treeitem.graphicProperty().bind( Bindings
   .when( treeitem.leafProperty() )
   .then( ivfolder )
   .otherwise( ( ImageView ) null ) 
);

// or set explicitly for that tree item
TreeItem<Folder> item = new TreeItem<>( "<empty>", ivfolder );

Don't forget to create new imageviews for every treeitem added to treeView and which needs that image.

Uluk Biy
  • 48,655
  • 13
  • 146
  • 153
  • I think, this image is not on the same vertical coordinate as the disclosure images. The image should be in front of (left of) the items graphic and text. I have tested a PseudoClass to toggle the background image of the disclosure node within CSS, but it doesn't work. – witchi Dec 04 '15 at 22:20
0

I have defined a css structure for the childless case:

.tree-cell:browser-folder-childless .tree-disclosure-node .arrow {
     -fx-font-weight: bold;
     -fx-shape: null;
     -fx-background-color: null;
     -fx-background-image: url("childless.png");
     -fx-background-repeat:  no-repeat;
}

.tree-cell:browser-folder-childless:expanded .tree-disclosure-node .arrow {
    -fx-font-weight: bold;
    -fx-shape: null;
    -fx-background-color: null;
    -fx-background-image: url("childless.png");
    -fx-background-repeat:  no-repeat;
}

Next I have extended the TreeItem class:

public class BrowserTreeItem extends TreeItem<MyData> {

    public BrowserTreeItem(MyData data) {
        super(data);
    }

    @Override
    public boolean isLeaf() {
        return (getValue().getTypes().contains(NodeType.FOLDER) && getValue().getChildren().size() == 0) ? false : super.isLeaf();
    }
}

So the TreeItem returns always false for isLeaf() in the case of a childless folder. The isLeaf() method will be used by the com.sun.javafx.scene.control.skin.TreeCellSkin.class to decide, whether or not the disclosure node should be removed. Rebuilding the node could be tricky, so I prevent the remove of the node.

This results in a normal disclosure node, now I have to change the image of the node.

It would be nice to overwrite also the isExanded() method of the TreeItem class. Then I would need only one CSS structure (the method would return always false for childless folders). But isExpanded() is final. So I cannot prevent the not/expanded switch by the user and I have to define two CSS structures.

Next, I have built a TreeCellFactory, which generates my own BrowserTreeCell classes. It toggles a PseudoClass state, which we use in the CSS above to activate some new images for the disclosure node.

public class BrowserTreeCell extends TreeCell<MyData> {

    private final PseudoClass childless = PseudoClass.getPseudoClass("browser-folder-childless");

    @Override
    protected void updateItem(MyData item, boolean empty) {
        super.updateItem(item, empty);

        if (!empty && item != null) {

            setText(item.getName());
            setGraphic(item.getThumbnail());
            setTooltip(item.getTooltip());

        } else {

            setText("");
            setGraphic(null);
            setTooltip(null);
        }

        pseudoClassStateChanged(childless, !empty && item != null && item.getTypes().contains(NodeType.FOLDER) && item.getChildren().size() == 0);

    }
}

As the result, I get a disclosure node with a "childless.png" in both cases (not/expanded).

witchi
  • 345
  • 3
  • 16
  • beware: now you have inconsistent state as leafProperty.get() != isLeaf() - even though you are in good/bad company with the motivating doc example in TreeItem, it's a bug in your code (as well as in the doc/accessibility of leafItem https://bugs.openjdk.java.net/browse/JDK-8089811). You might get away with it but should mark it heavily as such. – kleopatra Dec 10 '15 at 12:52