我现在正在教自己JavaFX,我已经采用了一个简单的示例程序,该程序硬编码视图并将其转换为使用FXML的程序(主要是因为我可以使用SceneBuilder来构建UI).我没有编写单独的控制器类,而是使用应用程序类(因此有1个Java文件和1个FXML文件).我没有使用initialize()方法,因为它是线性流(显示UI,填充字段,等待输入).弹出视图,但随后没有任何控件被映射到适当的变量,因此应用程序出错(因此@FXML TableView<...> table,table是null).
但是,我输入了一个initialize()调试方法,在进入时注入控件initialize(),然后在initialize()退出时返回null .
所以问题是,JavaFX是否将应用程序类的新实例实例化为单独的控制器类?这可以解释为什么变量超出范围.或者它是否是其他东西(例如,仅在从JavaFX动作回调时才注入控件)?
默认行为FXMLLoader是创建控制器类的新实例并将该实例用作控制器.
具体来说,它FXMLLoader做了类似的事情:
fx:controller属性,那么
fx:id属性,并且存在控制器(通过任何机制),则将这些字段注入控制器.类似地,将事件处理程序注册为对控制器实例中方法的调用.initialize()如果控制器存在并且它具有这样的方法,则在控制器上调用.所以,你问的问题是:
应用程序类可以是控制器类
是的,但这可能是一个糟糕的主意.如果您只是将Application子类指定为使用的控制器类fx:controller,则Application创建子类的第二个实例,在第二个实例上@FXML注入注释字段,并initialize()在该第二个实例上调用该方法.显然,@FXML-fields永远不会在start(...)调用的实例上初始化,并且永远不会在该实例上调用该initialize()方法.
你可能想要的问题是:
启动时创建的应用程序类实例可以用作控制器吗?
对此的答案也是肯定的,除了你打算立即丢弃的非常小的演示程序之外,它也可能是一个非常糟糕的主意.你会这样做的
public class MyApp extends Application {
@FXML
private Node someNode ;
public void initialize() {
// do something with someNode
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
loader.setController(this);
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,使用此代码,您FXML文件不得有fx:controller属性.
这样做的问题是你没有分离,没有灵活性.(例如,如果您在某处创建了FXML文件中定义的视图的第二个实例,则最终会得到第二Application个子类实例,这最好是违反直觉的(一个应用程序有两个Application实例......).)
所以我主张在每种情况下都为控制器使用一个单独的类.该Application子类应包含最少的代码和启动应用程序只应使用.
1这一步实际上有点复杂.如果在fx:controller属性中指定了类,并且没有控制器已存在,则FXMLLoader检查a controllerFactory.如果存在,则将控制器设置为将指定的方法传递Class给方法的结果,否则通过调用指定的类(有效地调用其无参数构造函数)来创建控制器.controllerFactorycall()newInstance()
| 归档时间: |
|
| 查看次数: |
2586 次 |
| 最近记录: |