我有一个JavaFX应用程序,它使用FXML和用Java编写的控制器类.在Java控制器中,我需要注意不要在FXML Node元素上进行操作,直到它被初始化(否则我会得到一个NullPointerException),这在initialize方法运行之前是不可保证的.所以我发现自己做了很多这样的事情:
控制器在FXML文件中设置如下:
<Pane fx:controller="Controller" ...>
...
</Pane>
Run Code Online (Sandbox Code Playgroud)
然后这是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
}
}
Run Code Online (Sandbox Code Playgroud)
这有效,但它很笨重,也很重复.我必须创建globalValue属性,以防万一setSomething调用之前的方法initialize,我必须确保我的setSomething方法中的操作与中的操作相同initialize.
当然,有一种更优雅的方式来做到这一点.我知道JavaFX有一个Platform.runlater(...)方法可以保证在主应用程序线程上运行一些东西.Perhpas有类似的东西Platform.runAfterInitialize(...)等到初始化,或者如果初始化已经发生则立即运行?或者,如果有另一种方法,我愿意接受建议.
Jam*_*s_D 11
如果在FXML文件中指定控制器fx:controller="Controller",则在调用时FXMLLoader.load(...),FXMLLoader:
Controller通过(有效地)调用其无参数构造函数创建一个实例(或者,在高级用法中,通过调用控制器工厂来设置它)fx:id到控制器实例中的匹配字段中initalize()在控制器实例上调用(如果定义了这样的方法)只有在load()结束(即之后的@FXML-annotated字段注入),你可以得到与控制器的参考loader.getController().因此,除了在控制器工厂实现中做一些非常不寻常的事情之外,您无法调用控制器实例上的任何方法,直到@FXML初始化了注入的字段.这里的空检查是多余的.
另一方面,如果您使用FXMLLoader.setController(...)初始化控制器,在这种情况下您不能使用fx:controller,您可以将值传递给构造函数.简单地避免set在将控制器传递给控制器之前调用控制器上的FXMLLoader方法,您可以假设任何@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
}
}
Run Code Online (Sandbox Code Playgroud)
和
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
Controller controller = new Controller(42);
loader.setController(controller);
Node root = loader.load();
Run Code Online (Sandbox Code Playgroud)