Javafx - 应用程序类可以是控制器类 [英] Javafx - Can application class be the controller class
问题描述
我目前正在自学JavaFX,我已经采用了一个简单的示例程序,该程序硬编码视图并将其转换为使用FXML的程序(主要是因为我可以使用SceneBuilder构建UI)。我没有编写单独的控制器类,而是使用应用程序类(因此有1个Java文件和1个FXML文件)。我没有使用 initialize()
方法,因为它是一个线性流(显示UI,填充字段,等待输入)。视图弹出,但随后应用程序出错,因为没有控件被映射到适当的变量(因此对于 @FXML TableView< ...> table
, table
是 null
)。
I'm currently teaching myself JavaFX, and I've taken a simple example program that's hardcoded the view and am turning it into one that uses FXML (mostly so I can use SceneBuilder for building UIs). Rather than writing a separate controller class, I'm using the application class (so there's 1 Java file and 1 FXML file). I'm not using an initialize()
method as it's a linear flow (display the UI, populate the fields, wait for input). The view pops up, but then the app errors out as none of the controls are mapped to the appropriate variables (so for @FXML TableView<...> table
, table
is null
).
但是,我放入了用于调试的 initialize()
方法,在 initialize()
中注入控件,然后在返回null时返回 initialize()
退出。
However, I put in an initialize()
method for debugging, the controls are injected while in initialize()
, and then return to null when initialize()
exits.
所以问题是,JavaFX是否将应用程序类的新实例实例化为单独的控制器类?这可以解释为什么变量超出范围。或者它是别的东西(例如,只有在从JavaFX动作回调时才注入控件)?
So the question is, does JavaFX instantiate a new instance of the application class as a separate controller class? This would explain why the variable are going out of scope. Or is it something else (e.g. the controls are injected only when being called back from JavaFX actions)?
推荐答案
默认行为 FXMLLoader
是创建控制器类的新实例并将该实例用作控制器。
The default behavior of the FXMLLoader
is to create a new instance of the controller class and use that instance as the controller.
具体来说, FXMLLoader
执行如下操作:
Specifically, the FXMLLoader
does something like:
- 读取根FXML元素。
- 如果根FXML元素具有
fx:controller
属性,则
- 如果控制器已存在,则抛出异常,否则创建指定类 1 的实例并将其设置为控制器
- Read the root FXML element.
- If the root FXML element has a
fx:controller
attribute, then- If a controller already exists, throw an exception, otherwise create an instance of the specified class1 and set that as the controller
所以,你问的问题是:
应用程序类可以是控制器类
Can application class be the controller class
是的,但这可能是一个糟糕的主意。如果只是使用
fx:controller
将Application
子类指定为控制器类,那么<$的第二个实例c $ c>应用程序创建子类,@FXML
- 在第二个实例上注入注释字段,初始化()
在第二个实例上调用方法。显然,@FXML
-fields永远不会在调用start(...)
的实例上初始化,并且永远不会在该实例上调用initialize()
方法。Yes, but it's probably a terrible idea. If you simply specify the
Application
subclass as the controller class usingfx:controller
, then a second instance of theApplication
subclass is created,@FXML
-annotated fields are injected on that second instance, and theinitialize()
method is invoked on that second instance. Obviously, the@FXML
-fields are never initialized on the instance on whichstart(...)
is invoked, and theinitialize()
method is never invoked on that instance.您可能想要的问题是:
启动时创建的应用程序类实例是否可以用作控制器?
Can the application class instance created at launch be used as the controller?
这个问题的答案也是肯定的,除了你打算立即丢弃的非常小的演示程序之外,它也可能是个坏主意。你可以这样做
The answer to this is also yes, and, aside from very small demo programs you intend to immediately discard, it's also probably a very bad idea. You would do this by
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(); } }
请注意,要使用此代码,您的FXML文件一定不能拥有
fx:controller
属性。Note that to use this code, your FXML file must not have a
fx:controller
attribute.这个问题就是你没有分离,没有灵活性。 (例如,如果您在某处创建了FXML文件中定义的视图的第二个实例,则最终会得到第二个
Application
子类实例,这最好是违反直觉的(一个应用程序两个应用程序
实例...)。)The problem with this is that you have no separation and no flexibility. (E.g. if you create a second instance of the view defined in your FXML file somewhere, you end up with a second
Application
subclass instance, which is at best counterintuitive (one application with twoApplication
instances...).)所以我主张基本上为控制器使用一个类每个案例。
应用程序
子类应包含最少的代码,并且只应用于启动应用程序。So I would advocate using a separate class for the controller in basically every case. The
Application
subclass should contain minimal code and should be used only for starting the application.1 这一步实际上有点复杂。如果在
fx:controller
属性中指定了类,并且没有控制器已存在,FXMLLoader
将检查< a href =http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader.html#setControllerFactory-javafx.util.Callback-\"rel =noreferrer>的ControllerFactory
。如果存在,则将控制器设置为将指定的Class
传递给controllerFactory
的call()
方法,否则通过在指定的类上调用newInstance()
来创建它(有效地调用它的无参数构造函数) )。1 This step is actually a little more complex. If a class is specified in the
fx:controller
attribute, and no controller already exists, theFXMLLoader
checks for acontrollerFactory
. If one exists, then the controller is set as the result of passing the specifiedClass
to thecontrollerFactory
'scall()
method, otherwise it is created by callingnewInstance()
on the specified class (effectively calling its no-argument constructor).这篇关于Javafx - 应用程序类可以是控制器类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- If the root FXML element has a
- 如果根FXML元素具有