如何将FX控制器与主应用程序连接

我有一个主应用程序类和一个fxmlController类,但我纠缠于连接/组织(混淆了如何调用它们以及我应该如何组织它们以使GUI连接业务逻辑)业务逻辑和GUI。有人可以告诉调用以下函数的顺序,或者任何人都可以帮助我如何调用它们吗?

主类:

public void Main()        //constructor
public static void main() // our main
public void start()       //I don't know what it is, what purpose it has
                          // and where should be called
                          //Note: In main function there is a call as following

fxmlController class:

public void initialize()  //I don't know what it is and what purpose it has
public fxmlController()   // which function should be called here....

注意:我知道请有人解释FXMLLoader();


答案 1

我将FXML文件及其相应的控制器视为管理用户界面的一对。在较大的应用程序中,您可能有几个这样的 FXML 控制器对,它们构成了用户界面的不同部分。在每对中,FXML文件定义UI的布局,控制器定义逻辑(即它通常处理用户输入等)。

虽然你说你“了解”,但如果你完全理解这一点,你实际上会理解你问的其他一些事情,所以:FXMLLoader

由 FXML 文件及其控制器定义的用户界面由 加载到内存中。在最简单的设置中,控制器由 FXML 文件的根元素中的属性定义。当在 上调用该方法时,它:FXMLLoaderfx:controllerload()FXMLLoader

  1. 加载 FXML 文件
  2. 通过调用其无参数构造函数,创建由该属性指定的控制器类的实例fx:controller
  3. 将控制器中任何带注释的字段的值设置为使用匹配属性定义的元素@FXMLfx:id
  4. 注册映射到控制器中的方法的任何事件处理程序
  5. 调用控制器上的方法(如果有)。initialize()

请注意这些事件的顺序:构造函数在注入 -annotated 字段之前调用,但在注入 -annoted 字段之后调用。这意味着您可以在方法中访问(和配置)和带批注的字段,但不能在构造函数中访问(和配置)字段。很常见(至少在简单的应用程序中),不在控制器类中定义任何构造函数,而只使用默认值。@FXMLinitialize()@FXMLinitialize()

您可以在应用程序中根据需要/想要拥有任意数量的 FXML/控制器对。每个 FXML 文件都应有自己的控制器类。如果需要 FXML 文件定义的 UI 的多个实例,则可以根据需要多次加载该文件:每次都会为您创建一个与加载的 UI 元素关联的新控制器实例。FXMLLoader

子类(您称之为 )表示整个应用程序。每个应用程序应该只有一个这样的类,并且只有一个由 FX 工具包为您创建的实例。ApplicationMain

当您启动 FX 应用程序(我将在下面描述)时,FX 工具包将启动。然后创建子类的实例,并调用其方法(如果未定义子类,则默认实现不执行任何操作)。然后启动 FX 应用程序线程,并在该线程上调用子类实例的方法。Applicationinit()Applicationstart()

您的方法应该可以完成非常少的工作。通常,它将加载“主”fxml 文件,将生成的 UI 放置在场景中,将场景放在舞台上,然后显示舞台。所有逻辑将由 FXML 文件的控制器处理,而不是由子类处理。start()Application

在更高级的应用程序中,您可以启动一些后台服务和/或在方法中创建一些数据模型,并将它们与方法中的控制器连接,但上述想法是基本的。init()start()

实际的启动过程可以通过几种方式发生。如果您使用的是标准 Oracle JRE,则使用Application

java Main

(其中 ) 将导致上述过程发生;换句话说,启动 FX 工具包,创建 一个实例,调用其方法,并在 FX 应用程序线程上调用其方法。Main extends ApplicationMaininit()start()

其他环境(特别是 IDE)不知道 JavaFX 启动过程,并且期望您正在执行的类具有方法,就像任何标准的 Java 应用程序类一样。为了支持这些环境,子类通常定义一个简单地调用的方法(继承自 的静态方法)。该方法强制启动 FX 工具包等。在任何应用程序生存期内,它只能调用一次。public static void main(String[] args)Applicationmain(...)launch(...)Applicationlaunch

所以现在你有这样的东西:

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");
    }
}

答案 2

控制器绑定在 fxml 文件中,或者您首次调用主视图的位置。

因此,您可以使用 xml 中的属性或启动器中的方法。fx:controllerFXMLLoader#setController()


推荐