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

问题描述 投票:5回答:2

我有一个主app类和一个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类:

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

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

java user-interface model-view-controller javafx fxml
2个回答
43
投票

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

虽然你说你“了解FXMLLoader”,如果你完全明白,你会真正了解你所问的其他一些事情,所以:

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

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

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

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

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

当您启动FX应用程序(我将在下面描述)时,FX工具包将启动。然后创建一个Application子类的实例,并调用它的init()方法(如果你没有定义一个,默认实现什么都不做)。然后启动FX应用程序线程,并在该线程上调用Application子类实例的start()方法。

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

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

实际的启动过程可以通过几种方式实现。如果您使用的是标准的Oracle JRE,那么启动一个Application子类

java Main

Main extends Application)将导致上述过程发生;换句话说,启动FX工具包,创建Main的实例,调用其init()方法,并在FX Application Thread上调用start()方法。

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

所以现在你有类似的东西:

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:controller属性或启动器中的FXMLLoader#setController()方法。

© www.soinside.com 2019 - 2024. All rights reserved.