简体   繁体   English

JavaFX - 将FXML包装到Java类控制器

[英]JavaFX - Wrapping FXML to Java Class Controller

I have a FXML file that has a TreeView control: 我有一个具有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" />

Then my Java Class Controller needs to wrap with this TreeView and add TreeItem's dynamically. 然后我的Java类控制器需要用这个TreeView包装并动态添加TreeItem。 That's the problem, it isn't loading those TreeItem's. 这就是问题,它没有加载那些TreeItem。 That's the test code below, from my 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);
    }
}

Any ideas why its not working? 任何想法为什么它不工作?

There are a couple of reasons why your application doesn't work: 您的应用程序不起作用的原因有以下几种:

  1. You need to make the Controller and the Application separate classes. 您需要使Controller和Application分开。
  2. You should allow the FXML system to inject the TreeView instance rather than creating a new instance (as Aaron points out in his answer). 您应该允许FXML系统注入TreeView实例而不是创建新实例(正如Aaron在他的回答中指出的那样)。

The way you have your application currently structured what will happen is: 您的应用程序当前结构化的方式将是:

  1. The Java system will create an instance of MyControllerClass on startup (and invoke it's start method). Java系统将在启动时创建MyControllerClass的实例(并调用它的start方法)。
  2. The FXMLLoader will create another instance of MyControllerClass each time the myInterface.fxml file is loaded. 每次加载myInterface.fxml文件FXMLLoader都会创建另一个 MyControllerClass 实例
  3. The FXMLLoader will create a new TreeView instance and perform the FXML injection on the locationTreeView member of the new MyControllerClass instance it creates. FXMLLoader将创建一个新的TreeView实例,并在它创建的 MyControllerClass实例的locationTreeView成员上执行FXML注入。
  4. The FXMLLoader will try to invoke the initialize method on the new MyControllerClass (of which you have none). FXMLLoader将尝试在新的MyControllerClass上调用initialize方法(其中没有)。
  5. The FXMLLoader will not invoke the start method on the new MyControllerClass . FXMLLoader 不会新的 MyControllerClass上调用start方法。
  6. Your original start method invocation on your original MyControllerClass will continue processing and create another new TreeView instance which it will set the locationTreeView member of the old MyControllerClass instance to. 原始MyControllerClass上的原始start方法调用将继续处理并创建另一个新的 TreeView实例,它将 MyControllerClass实例的locationTreeView成员设置为。

I updated your code to make the modifications I suggested above and the code now works. 我更新了您的代码以进行上面建议的修改,现在代码可以正常工作。 The updated code is available . 更新的代码可用

A sample screenshot from the running code is: 运行代码的示例屏幕截图如下: dynamictreeview

MyApplicationClass.java 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 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 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>

In your loadTreeItems() function you are creating a new TreeView instance. 在loadTreeItems()函数中,您将创建一个新的TreeView实例。 This is replacing the one that is defined in your FXML file and attached to your scene with a new instance that is not part of the scene graph. 这将替换FXML文件中定义的并使用不属于场景图的新实例附加到场景的那个。

To add items to a TreeView that was created via the FXMLLoader you can use the setRoot() function. 要将项添加到通过FXMLLoader创建的TreeView,您可以使用setRoot()函数。

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.setRoot(root);

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM