示例 FXML

一個簡單的 FXML 文件,概述了包含按鈕和標籤節點的 AnchorPane

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" 
        fx:controller="com.example.FXMLDocumentController">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
    </children>
</AnchorPane>

此示例 FXML 檔案與控制器類相關聯。在這種情況下,FXML 和控制器類之間的關聯是通過在 FXML 的根元素中指定類名作為 fx:controller 屬性的值來實現的:fx:controller="com.example.FXMLDocumentController"。控制器類允許執行 Java 程式碼以響應對 FXML 檔案中定義的 UI 元素的使用者操作:

package com.example ;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

public class FXMLDocumentController {
    
    @FXML
    private Label label;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }
    
    @Override
    public void initialize(URL url, ResourceBundle resources) {
        // Initialization code can go here. 
        // The parameters url and resources can be omitted if they are not needed
    }    
    
}

FXMLLoader 可用於載入 FXML 檔案:

public class MyApp extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("FXMLDocument.fxml"));
        Parent root = loader.load();
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

}

load 方法執行多個操作,瞭解它們發生的順序很有用。在這個簡單的例子中:

  1. FXMLLoader 讀取並解析 FXML 檔案。它建立與檔案中定義的元素對應的物件,並記下在其上定義的任何 fx:id 屬性。

  2. 由於 FXML 檔案的根元素定義了 fx:controller 屬性,因此 FXMLLoader 建立了它指定的類的新例項。預設情況下,這是通過在指定的類上呼叫無參建構函式來實現的。

  3. 定義了 fx:id 屬性的任何元素,其中控制器中的欄位具有匹配的欄位名稱,並且 public(不推薦)或帶註釋的 @FXML(推薦)被注入到那些相應的欄位中。所以在這個例子中,因為 FXML 檔案中有一個 Label,其中 fx:id="label" 和控制器中的一個欄位定義為

    @FXML
    private Label label ;
    

    label 欄位使用 FXMLLoader 建立的 Label 例項進行初始化。

  4. 事件處理程式在 FXML 檔案中的任何元素中註冊,並定義了 onXXX="#..." 屬性。這些事件處理程式呼叫控制器類中的指定方法。在這個例子中,由於 Button 具有 onAction="#handleButtonAction",並且控制器定義了一種方法

    @FXML
    private void handleButtonAction(ActionEvent event) { ... }
    

    當對按鈕觸發動作時(例如,使用者按下它),將呼叫此方法。該方法必須具有 void 返回型別,並且可以定義與事件型別匹配的引數(在此示例中為 ActionEvent),或者可以不定義任何引數。

  5. 最後,如果控制器類定義了 initialize 方法,則呼叫此方法。請注意,這是在注入 @FXML 欄位後發生的,因此可以在此方法中安全地訪問它們,並使用與 FXML 檔案中的元素對應的例項進行初始化。initialize() 方法既可以不引數,也可以採用 URLResourceBundle。在後一種情況下,這些引數將由表示 FXML 檔案位置的 URL 以及通過 loader.setResources(...)FXMLLoader 上設定的任何 ResourceBundle 填充。如果沒有設定,這些中的任何一個都可以是 null