Search code examples
javafxfxml

Customizing TreeCells using cell factory


I am trying to represent a TreeCell like this:

tree cell

I have tried reading up on cell factories and I know I have to use this functionality. But how can I set the graphics to be like this for all the TreeCells? The image is stored as an HBox in an .fxml-file.

Thank you so much :)

P.S. Not necessarily looking for code in the answer here, more of a general explanation as to how to do this or why it doesn't work.

This is the code I have tried. The fxml file is in the same folder as the file.

This is the error code I get:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Location is required.

    @Override
public void updateItem(String item, boolean empty) {
   super.updateItem(item, empty);
    try {
        this.hBox = (HBox) FXMLLoader.load(getClass().getResource("/Views/TreeCell.fxml"));
    } catch (IOException e) {
        System.out.println("This didn't work");
        e.printStackTrace();
    }
    if (item != null) {
        setGraphic(this.hBox);
    } else {
        setGraphic(null);
    }
}

Solution

  • The exception you are getting just means that the FXMLLoader can't find the FXML file you specified. If the FXML file is in the same package as the current class, you should be able to use

        this.hBox = (HBox) FXMLLoader.load(getClass().getResource("TreeCell.fxml"));
    

    If you start the resource path with a leading /, it will be interpreted as relative to the classpath.

    Performance is likely to be pretty poor using the code you show. When using cell factories, the cells are created relatively rarely, but their updateItem(...) methods may be called quite frequently (especially during rapid scrolling, or while expanding and collapsing tree nodes). It's probably a bad idea to be reading and parsing an FXML file in that method.

    Instead, you can read the file once when the cell is created, and then just reuse the resulting HBox in the updateItem() method:

    tree.setCellFactory(treeView -> {
        HBox hbox ;
        try {
            hbox = (HBox) FXMLLoader.load(getClass().getResource("TreeCell.fxml"));
        } catch (Exception exc) {
            throw new RuntimeException(exc) ;
        }
        return new TreeCell<String>() {
            @Override
            public void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null) {
                    setGraphic(null);
                } else {
                    // configure graphic with cell data etc...
                    setGraphic(hbox);
                }
            }
        };
    });