Java FX 2 TreeView模型参考

时间:2013-05-20 21:40:10

标签: javafx-2 javafx

我想在TreeItem事件期间取回valueProperty s onMouseClick。我有TreeView以下类型:

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

FXML如下:

<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" />

我想在点击时取回我的模型(Pair实例)。

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

在我的案例中,目标对象是Label文本,据我所知,它不包含封装的模型引用。有人可以建议吗?这似乎是一个非常基本的特征。单向绑定......带有某种参考。我不打算编辑TreeItem

此主题似乎与问题相似: Model-Identifier for Node in JavaFX 2 TreeItem

由于

1 个答案:

答案 0 :(得分:9)

关键是在TreeView上定义cell factory,在单元工厂中将鼠标单击事件处理程序添加到树单元格中。如此定义的鼠标单击事件处理程序将具有对支持树单元格的模型对象的完全访问权限,并且可以使用它执行所需的操作。

在下面的示例中,当用户单击树中的单元格时,单击处理程序从与所单击的单元格相关的基础模型项中提取信息,并将该信息呈现到树下的标签中。

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>

<强>更新

  

这很好用。但是,一旦我们设置了CallBack事件处理程序,图标图像似乎就会丢失。

是的,看起来如果你创建自己的细胞工厂,你还需要在细胞工厂内手动设置图形。这是因为默认树项单元工厂将从树项中获取图形(如果已在树项上设置了该图形),而此逻辑将不会出现在自定义单元工厂中,除非您在那里进行编码。

我更新了示例解决方案中的代码,以展示如何在自定义单元工厂生成的树单元格上设置图形。更新后的代码从支持树单元格的模型中获取图形图像,但是如果首选,则可以从树项目的图形属性中检索它。要从TreeItem获取图形,请使用blacks0ul建议的以下代码:

TreeItem<Pair<URIImpl, String>> item = getTreeItem();
if (item != null && item.getGraphic() != null) { 
  setGraphic(item.getGraphic()); 
}