The key is to define the cell factory in the TreeView and in the factory cell add a click event handler to the tree cell. The mouse click event handler defined in this way will have full access to the model object that supports the tree cell and can do something with it.
In the example below, when a user clicks cells in a tree, click handlers extract information from the base model element associated with the pressed cell and display this information in a label under the tree.

TreeApplication.java
import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.*; import javafx.stage.*; public class TreeApplication extends Application { @Override public void start(final Stage stage) throws Exception { final FXMLLoader loader = new FXMLLoader( getClass().getResource("treeInterface.fxml") ); final Parent root = (Parent) loader.load(); stage.setScene(new Scene(root)); stage.show(); } public static void main(String[] args) { launch(args); } }
TreeController.java
import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.util.Callback; import javafx.util.Pair; import java.net.URL; import java.util.ResourceBundle; public class TreeController implements Initializable { @FXML private TreeView<Pair<URIImpl,String>> treeView; @FXML private Label clickedPair; @Override public void initialize(URL location, ResourceBundle resources) { treeView.setCellFactory(new Callback<TreeView<Pair<URIImpl, String>>, TreeCell<Pair<URIImpl, String>>>() { @Override public TreeCell<Pair<URIImpl, String>> call(TreeView<Pair<URIImpl, String>> treeView) { return new TreeCell<Pair<URIImpl, String>>() { final ImageView iconView = new ImageView(); @Override protected void updateItem(final Pair<URIImpl, String> pair, boolean empty) { super.updateItem(pair, empty); if (!empty && pair != null) { setText( pair.getValue() ); setGraphic( iconView ); iconView.setImage(pair.getKey().getImage()); } else { setText(null); setGraphic(null); } setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { clickedPair.setText( "Key: " + pair.getKey() + " Value: " + pair.getValue() ); } }); } }; } }); loadTreeItems( createPair("http://www.google.com", "google.com", "Google"), createPair("http://www.microsoft.com", "microsoft.com", "Microsoft"), createPair("http://www.yahoo.com", "yahoo.com", "Yahoo") ); } private Pair<URIImpl, String> createPair(String uri, String domain, String name) { return new Pair<>(new URIImpl(uri, domain), name); } private void loadTreeItems(Pair<URIImpl,String>... rootItems) { TreeItem<Pair<URIImpl,String>> root = new TreeItem(createPair("N/A", "", "Root Node")); root.setExpanded(true); for (Pair<URIImpl, String> pair: rootItems) { root.getChildren().add( new TreeItem<>( pair ) ); } treeView.setRoot(root); } }
URIImpl.java
import javafx.scene.image.Image; class URIImpl { private final String uri; private final String domain; private Image image; public URIImpl(String uri, String domain) { this.uri = uri; this.domain = domain; } public String getUri() { return uri; } public String getDomain() { return domain; } public Image getImage() { if (image == null) { image = new Image("https://plus.google.com/_/favicon?domain=" + getDomain()); } return image; } @Override public String toString() { return "URIImpl{" + "uri->" + uri + '}'; } }
treeInterface.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns:fx="http://javafx.com/fxml" fx:controller="tests.treesample.TreeController"> <TreeView fx:id="treeView" layoutX="0" layoutY="0" prefHeight="193.0" prefWidth="471.0" /> <Label fx:id="clickedPair" layoutX="0" layoutY="200"/> </AnchorPane>
Update
Everything went perfectly. However, the icon image appears lost after we configure CallBack event handlers.
Yes, it looks like if you create your own factory cell, you also need to set the graphics manually in the factory cell. This is because, by default, the factory cell cell will capture graphics from the tree element if it was installed in the tree element, while this logic will not be present in your custom factory cell if you do not code it there.
I updated the code in the sample to show how you can set the graphics in a tree cell generated by a custom factory cell. The updated code receives a graphic image from a model that supports a tree-cell, but equally, he could get it from the graph attribute of a tree element, if this was preferable. To get graphics from TreeItem, use the following code as suggested by blacks0ul:
TreeItem<Pair<URIImpl, String>> item = getTreeItem(); if (item != null && item.getGraphic() != null) { setGraphic(item.getGraphic()); }