6

我正在尝试在活动期间取回TreeItems 。我有以下类型:valuePropertyonMouseClickTreeView

@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不包含封装模型引用的文本。有人可以建议吗?这似乎是一个非常基本的特征。一种单向绑定...带有某种参考。我不打算编辑TreeItems。

该线程似乎类似于问题: JavaFX 2 TreeItem 中节点的模型标识符

谢谢

4

1 回答 1

9

关键是在 TreeView 上定义一个单元工厂,并在单元工厂中将鼠标单击事件处理程序添加到树单元。如此定义的鼠标单击事件处理程序将具有对支持树单元的模型对象的完全访问权限,并且可以对其进行任何操作。

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

树模型

树应用程序.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); }
}

树控制器.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 + '}';
  }    
}

树接口.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()); 
} 
于 2013-05-21T00:54:48.487 回答