Java FX 2 TreeView Template Reference

I am trying to return a TreeItem valueProperty during an onMouseClick event. I have a TreeView following type:

 @FXML private TreeView<Pair<URIImpl,String>> myTreeview; 

FXML as follows:

 <TreeView fx:id="myTreeview" onMouseClicked="#myTreeview_Clicked" prefHeight="551.0" prefWidth="166.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> 

I would like to return my model ( Pair instance) when clicked.

 void myTreeview_Clicked(MouseEvent event) { if(event.getTarget() instanceof ...) { // Fetch Target } } 

The target in my case is Label text that does not contain an encapsulated model reference, as far as I know. Can anyone consult? This is, apparently, a very fundamental feature. One way binding ... with some link. I do not want to edit TreeItem s.

This thread is similar to the question: Model ID for Node in JavaFX 2 TreeItem

thanks

+6
source share
1 answer

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.

treemodel

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()); } 
+9
source

Source: https://habr.com/ru/post/945459/


All Articles