我有一个JavaFX应用程序,它使用FXML和用Java编写的控制器类。在Java控制器中,我需要注意不要在FXML Node
元素上进行操作,直到它被初始化(否则我会得到NullPointerException),这是不能保证的,直到运行initialize
方法。所以我发现自己做了很多这样的事情:
控制器设置在 FXML文件中,如下所示:
<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
属性,以防在调用setSomething
之前调用initialize
方法,并且我必须确保setSomething
方法中的操作是与initialize
中的操作相同。
当然,这是一种更优雅的方式。我知道JavaFX有Platform.runlater(...)
方法,可以保证在主应用程序线程上运行某些东西。 Perhpas那里有类似Platform.runAfterInitialize(...)
的东西等到初始化,或者如果初始化已经发生则立即运行?或者,如果有另一种方法,我可以接受建议。
答案 0 :(得分:10)
如果您使用fx:controller="Controller"
在FXML文件中指定控制器,那么当您致电FXMLLoader.load(...)
时,FXMLLoader
:
Controller
的实例(或者,在高级用法中,通过调用控制器工厂来设置它)fx:id
的所有元素注入控制器实例中的匹配字段initalize()
(如果定义了这样的方法)只有在load()
完成后(即 注入@FXML
- 注释字段后)才能获得对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
}
}
和
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
Controller controller = new Controller(42);
loader.setController(controller);
Node root = loader.load();