FXML:“初始化后运行”
我有一个JavaFX应用程序,它使用FXML和用Java编写的控制器类。 在Java控制器中,我需要注意不要在FXML Node
元素上进行操作,直到它被初始化(否则我会得到一个NullPointerException),这在initialize
方法运行之前是无法保证的。 所以我发现自己做了很多事情:
控制器在FXML文件中设置如下:
...
然后这是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
方法,并且我必须确保setSomething
方法中的操作与initialize
的操作相同。
当然有更优雅的方式来做到这一点。 我知道JavaFX有Platform.runlater(...)
方法,可以保证在主应用程序线程上运行一些东西。 Perhpas有像Platform.runAfterInitialize(...)
这样的东西,等到初始化,或者如果初始化已经发生则立即运行? 或者,如果有另一种方法可以做到这一点,我愿意接受建议。
如果使用fx:controller="Controller"
在FXML文件中指定fx:controller="Controller"
,那么当您调用FXMLLoader.load(...)
, FXMLLoader
:
- 解析FXML文件
- 通过(有效地)调用其无参数构造函数来创建一个
Controller
实例(或者,在高级用法中,通过调用控制器工厂来设置它) - 创建与FXML文件中的元素对应的UI元素
- 将具有
fx:id
任何元素注入到控制器实例中的匹配字段中 - 注册事件处理程序
- 在控制器实例上调用
initalize()
(如果定义了这样的方法) - 返回与FXML层次结构的根对应的UI元素
只有在load()
完成后(即在注入@FXML
字段之后 ),才能使用loader.getController()
获得对控制器的引用。 因此,除了在控制器工厂实现中做一些非常不寻常的事情之外,您无法调用控制器实例上的任何方法,直到初始化@FXML
字段之后。 这里的空检查是多余的。
另一方面,如果您使用FXMLLoader.setController(...)
来初始化控制器,在这种情况下您不能使用fx:controller
,您可以将值传递给构造函数。 在将控制器传递给FXMLLoader
之前,简单地避免在控制器上调用set
方法意味着您可以假设在控制器的公共方法中初始化了任何@FXML
字段:
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();