我有一个具有TreeView控件的FXML文件:

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass">

<TreeView fx:id="locationTreeView" layoutX="12.0" layoutY="158.0" prefHeight="193.0" prefWidth="471.0" />

然后,我的Java类 Controller 需要使用此TreeView包装并动态添加TreeItem。这就是问题所在,它没有加载那些TreeItem。这是来自我的 Controller 的以下测试代码:
public class MyControllerClass extends Application {

    @FXML
    private TreeView<String> locationTreeView;

    @Override
    public void start(Stage stage) throws Exception {

        stage.initStyle(StageStyle.TRANSPARENT);
        stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png")));

        Parent root = FXMLLoader.load(getClass().getResource("myInterface.fxml"));

        Scene scene = new Scene(root);
        stage.setScene(scene);

        loadTreeItems();

        stage.show();
    }

    // Just a simple example that still doesn't works
    private void loadTreeItems() {

        try {
            TreeItem<String> root = new TreeItem<String>("Root Node");
            root.setExpanded(true);
            root.getChildren().addAll(
                new TreeItem<String>("Item 1"),
                new TreeItem<String>("Item 2"),
                new TreeItem<String>("Item 3")
            );

            locationTreeView = new TreeView<String>(root);

        } catch (Exception exc) {
            System.out.println("Error: " + exc.getMessage());
        }
    }

    public static void main(String[] args) {
         launch(args);
    }
}

任何想法为什么它不起作用?

最佳答案

您的应用程序无法正常工作的原因有两个:

  • 您需要将Controller和Application分开设置类。
  • 您应该允许FXML系统注入(inject)TreeView实例,而不是创建一个新实例(正如Aaron在他的回答中指出的那样)。

  • 当前使应用程序结构化的方式将是:
  • Java系统将在启动时创建MyControllerClass的实例(并调用它的start方法)。
  • 每次加载FXMLLoader文件时,MyControllerClass将创建另一个myInterface.fxml实例。
  • FXMLLoader将创建一个新的TreeView实例,并对其创建的新locationTreeView实例的MyControllerClass成员执行FXML注入(inject)。
  • FXMLLoader将尝试在新的initialize(您没有)上调用MyControllerClass方法。
  • FXMLLoader将不会在新的start上调用MyControllerClass方法。
  • 对原始start的原始MyControllerClass方法调用将继续处理并创建另一个新的TreeView实例,它将把旧locationTreeView实例的MyControllerClass成员设置为该实例。


  • 我更新了您的代码,以进行上面建议的修改,现在代码可以正常工作了。更新的code is available

    运行代码的示例屏幕截图为:

    MyApplicationClass.java
    import javafx.animation.*;
    import javafx.application.Application;
    import javafx.event.*;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.*;
    import javafx.scene.image.Image;
    import javafx.scene.input.MouseEvent;
    import javafx.stage.*;
    import javafx.util.Duration;
    
    /** Sample application to demonstrate programming an FXML interface. */
    public class MyApplicationClass extends Application {
      @Override public void start(final Stage stage) throws Exception {
        // load the scene fxml UI.
        // grabs the UI scenegraph view from the loader.
        // grabs the UI controller for the view from the loader.
        final FXMLLoader loader = new FXMLLoader(getClass().getResource("myInterface.fxml"));
        final Parent root = (Parent) loader.load();
        final MyControllerClass controller = loader.<MyControllerClass>getController();
    
        // continuously refresh the TreeItems.
        // demonstrates using controller methods to manipulate the controlled UI.
        final Timeline timeline = new Timeline(
          new KeyFrame(
            Duration.seconds(3),
            new TreeLoadingEventHandler(controller)
          )
        );
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    
        // close the app if the user clicks on anywhere on the window.
        // just provides a simple way to kill the demo app.
        root.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
          @Override public void handle(MouseEvent t) {
            stage.hide();
          }
        });
    
        // initialize the stage.
        stage.setScene(new Scene(root));
        stage.initStyle(StageStyle.TRANSPARENT);
        stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png")));
        stage.show();
      }
    
      /** small helper class for handling tree loading events. */
      private class TreeLoadingEventHandler implements EventHandler<ActionEvent> {
        private MyControllerClass controller;
        private int idx = 0;
    
        TreeLoadingEventHandler(MyControllerClass controller) {
          this.controller = controller;
        }
    
        @Override public void handle(ActionEvent t) {
          controller.loadTreeItems("Loaded " + idx, "Loaded " + (idx + 1), "Loaded " + (idx + 2));
          idx += 3;
        }
      }
    
      // main method is only for legacy support - java 8 won't call it for a javafx application.
      public static void main(String[] args) { launch(args); }
    }
    

    MyControllerClass.java
    import javafx.fxml.FXML;
    import javafx.scene.control.*;
    
    /** Sample controller class. */
    public class MyControllerClass {
      // the FXML annotation tells the loader to inject this variable before invoking initialize.
      @FXML private TreeView<String> locationTreeView;
    
      // the initialize method is automatically invoked by the FXMLLoader - it's magic
      public void initialize() {
        loadTreeItems("initial 1", "initial 2", "initial 3");
      }
    
      // loads some strings into the tree in the application UI.
      public void loadTreeItems(String... rootItems) {
        TreeItem<String> root = new TreeItem<String>("Root Node");
        root.setExpanded(true);
        for (String itemString: rootItems) {
          root.getChildren().add(new TreeItem<String>(itemString));
        }
    
        locationTreeView.setRoot(root);
      }
    }
    

    myInterface.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="test.MyControllerClass">
      <TreeView fx:id="locationTreeView" layoutX="0" layoutY="0" prefHeight="193.0" prefWidth="471.0" />
    </AnchorPane>
    

    10-08 12:54