FXML:“初始化后运行” [英] FXML: "Run after initialized"

查看:325
本文介绍了FXML:“初始化后运行”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JavaFX应用程序,它使用FXML和用Java编写的控制器类。在Java控制器中,我需要注意不要在FXML Node 元素上运行,直到它被初始化(否则我会得到一个NullPointerException),直到运行 initialize 方法。所以我发现自己做了很多这样的事情:

I have a JavaFX application that uses FXML alongside a controller class written in Java. In the Java controller I need to take care not to operate on an FXML Node element until it's been initialized (otherwise I'll get a NullPointerException), which isn't guaranteed until the initialize method is run. So I find myself doing this a lot:

控制器设置在 FXML文件中,如下所示:

The controller is set in the FXML file like this:

<Pane fx:controller="Controller" ...>
...
</Pane>

然后这是 Java文件中的控制器。

class Controller{
    @FXML
    Pane aPane;
    int globalValue;

    public void setSomething(int value){
        globalValue = value;
        if(!(aPane == null)){  //possibly null if node not initialized yet
            aPane.someMethod(globalValue)
        }
    }

    @FXML
    void initialize(){
        aPane.someMethod(globalValue) //guaranteed not null at this point
    }


}

这样可行,但它很笨重且重复。我必须创建 globalValue 属性,以防在 initialize <之前调用 setSomething 方法/ code>已被调用,我必须确保我的 setSomething 方法中的操作与 initialize中的操作相同

This works, but it's clunky and repetitive. I have to create the globalValue attribute just in case the setSomething method is called before initialize has been called, and I have to make sure the operations in my setSomething method are identical to the operations in initialize.

肯定有更优雅的方式来做到这一点。我知道JavaFX有 Platform.runlater(...)方法,可以保证在主应用程序线程上运行某些东西。 Perhpas有类似 Platform.runAfterInitialize(...)等待初始化,或者如果初始化已经发生则立即运行?或者,如果还有另一种方法,我愿意接受建议。

Surely there's a more elegant way to do this. I know that JavaFX has the Platform.runlater(...) method that guarantees something will be run on the main application thread. Perhpas there's something like Platform.runAfterInitialize(...) that waits until initialization, or runs immediately if initialization already happened? Or if there's another way to do it I'm open to suggestions.

推荐答案

如果在FXML文件中指定控制器 fx:controller =Controller,然后当你拨打 FXMLLoader.load(...)时, FXMLLoader

If you specify the controller in the FXML file with fx:controller="Controller", then when you call FXMLLoader.load(...), the FXMLLoader:


  1. 解析FXML文件

  2. 通过(有效地)调用其无参数构造函数来创建 Controller 的实例(或者,在高级用法中,通过调用控制器工厂来设置它)

  3. 创建与FXML文件中的元素对应的UI元素

  4. 使用 fx:id 注入任何元素进入控制器实例中的匹配字段

  5. 注册事件处理程序

  6. 调用 initalize() on控制器实例(如果定义了这样的方法)

  7. 返回对应于FXML层次结构根的UI元素

  1. parses the FXML file
  2. creates an instance of Controller by (effectively) calling its no-arg constructor (or, in advanced usage, by invoking the controller factory if you set one)
  3. creates the UI elements corresponding to the elements in the FXML file
  4. injects any elements with an fx:id into matching fields in the controller instance
  5. registers event handlers
  6. invokes initalize() on the controller instance (if such a method is defined)
  7. returns the UI element corresponding to the root of the FXML hierarchy

仅在加载后()完成(即 @FXML 注释字段后注入)可以使用 loader.getController()获取对控制器的引用。因此,除了在控制器工厂实现中做一些非常不寻常的事情之外,你不可能调用控制器实例上的任何方法,直到 @FXML -injected字段为止初始化。这里的空检查是多余的。

Only after load() completes (i.e. after the @FXML-annotated fields are injected) can you get a reference to the controller with loader.getController(). So it is not possible (aside from doing something extremely unusual in a controller factory implementation) for you to invoke any methods on the controller instance until after the @FXML-injected fields are initialized. Your null checks here are redundant.

另一方面,如果你使用 FXMLLoader.setController (...)初始化你的控制器,在这种情况下你不能使用 fx:controller ,你可以将值传递给构造函数。在将控制器传递给 FXMLLoader 之前,简单地避免在控制器上调用 set 方法意味着你可以假设任何 @FXML -annotated字段在控制器的公共方法中初始化:

On the other hand, if you use FXMLLoader.setController(...) to initialize your controller, in which case you must not use fx:controller, you can pass the values to the constructor. Simply avoiding calling a set method on the controller before passing the controller to the FXMLLoader means you can assume any @FXML-annotated fields are initialized in the controller's public methods:

class Controller{
    @FXML
    Pane aPane;
    int globalValue;

    public Controller(int globalValue) {
        this.globalValue = globalValue ;
    }

    public Controller() {
        this(0);
    }

    public void setSomething(int value){
        globalValue = value;
        aPane.someMethod(globalValue)
    }

    @FXML
    void initialize(){
        aPane.someMethod(globalValue) //guaranteed not null at this point
    }


}

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
Controller controller = new Controller(42);
loader.setController(controller);
Node root = loader.load();

这篇关于FXML:“初始化后运行”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆