我将FXML文件及其相应的控制器视为管理用户界面的一对。在较大的应用程序中,您可能有几个这样的 FXML 控制器对,它们构成了用户界面的不同部分。在每对中,FXML文件定义UI的布局,控制器定义逻辑(即它通常处理用户输入等)。
虽然你说你“了解”,但如果你完全理解这一点,你实际上会理解你问的其他一些事情,所以:FXMLLoader
由 FXML 文件及其控制器定义的用户界面由 加载到内存中。在最简单的设置中,控制器由 FXML 文件的根元素中的属性定义。当在 上调用该方法时,它:FXMLLoader
fx:controller
load()
FXMLLoader
- 加载 FXML 文件
- 通过调用其无参数构造函数,创建由该属性指定的控制器类的实例
fx:controller
- 将控制器中任何带注释的字段的值设置为使用匹配属性定义的元素
@FXML
fx:id
- 注册映射到控制器中的方法的任何事件处理程序
- 调用控制器上的方法(如果有)。
initialize()
请注意这些事件的顺序:构造函数在注入 -annotated 字段之前调用,但在注入 -annoted 字段之后调用。这意味着您可以在方法中访问(和配置)和带批注的字段,但不能在构造函数中访问(和配置)字段。很常见(至少在简单的应用程序中),不在控制器类中定义任何构造函数,而只使用默认值。@FXML
initialize()
@FXML
initialize()
您可以在应用程序中根据需要/想要拥有任意数量的 FXML/控制器对。每个 FXML 文件都应有自己的控制器类。如果需要 FXML 文件定义的 UI 的多个实例,则可以根据需要多次加载该文件:每次都会为您创建一个与加载的 UI 元素关联的新控制器实例。FXMLLoader
子类(您称之为 )表示整个应用程序。每个应用程序应该只有一个这样的类,并且只有一个由 FX 工具包为您创建的实例。Application
Main
当您启动 FX 应用程序(我将在下面描述)时,FX 工具包将启动。然后创建子类的实例,并调用其方法(如果未定义子类,则默认实现不执行任何操作)。然后启动 FX 应用程序线程,并在该线程上调用子类实例的方法。Application
init()
Application
start()
您的方法应该可以完成非常少的工作。通常,它将加载“主”fxml 文件,将生成的 UI 放置在场景中,将场景放在舞台上,然后显示舞台。所有逻辑将由 FXML 文件的控制器处理,而不是由子类处理。start()
Application
在更高级的应用程序中,您可以启动一些后台服务和/或在方法中创建一些数据模型,并将它们与方法中的控制器连接,但上述想法是基本的。init()
start()
实际的启动过程可以通过几种方式发生。如果您使用的是标准 Oracle JRE,则使用Application
java Main
(其中 ) 将导致上述过程发生;换句话说,启动 FX 工具包,创建 一个实例,调用其方法,并在 FX 应用程序线程上调用其方法。Main extends Application
Main
init()
start()
其他环境(特别是 IDE)不知道 JavaFX 启动过程,并且期望您正在执行的类具有方法,就像任何标准的 Java 应用程序类一样。为了支持这些环境,子类通常定义一个简单地调用的方法(继承自 的静态方法)。该方法强制启动 FX 工具包等。在任何应用程序生存期内,它只能调用一次。public static void main(String[] args)
Application
main(...)
launch(...)
Application
launch
所以现在你有这样的东西:
package com.example ;
// imports...
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// just load fxml file and display it in the stage:
FXMLLoader loader = new FXMLLoader(getClass().getResource("mainUI.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
// main method to support non-JavaFX-aware environments:
public static void main(String[] args) {
// starts the FX toolkit, instantiates this class,
// and calls start(...) on the FX Application thread:
launch(args);
}
}
然后你会有mainUI.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import java.util.ArrayList?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.MyController">
<Label fx:id="label1"/>
<Label fx:id="label2"/>
</VBox>
和控制器
package com.example ;
// imports...
public class MyController {
@FXML
private Label label1 ;
@FXML
private Label label2 ;
// called by the FXML loader after the labels declared above are injected:
public void initialize() {
// do initialization and configuration work...
// trivial example, could also be done directly in the fxml:
label1.setText("Foo");
label2.setText("Bar");
}
}