JavaFX FXML 載入異常的解決方法
本教程介紹導致 JavaFX FXML 載入異常的原因並提供快速解決方案。
導致 JavaFX FXML 載入異常的原因
獲得 JavaFX FXML 載入異常的第一個原因是 FXML 檔案的路徑未正確指定給載入程式。路徑 /fxml/view.fxml
指的是一個名為 fxml
的資料夾中的檔案 view.fxml
,該資料夾位於 resources
資料夾中,即在 classpath
上。
getClass().getResource()
呼叫在執行時呼叫物件 classloader
,它在 classpath
中搜尋傳遞給它的資源。這樣,它將在該資料夾中找到 fxml
資料夾和 view.fxml
檔案。
第二個原因可能是元件 ID 不匹配,這意味著我們可能已經更新了 Controller
檔案中的元件 ID,但忘記在 FXML 檔案中更改該 ID(反之亦然)。在這種情況下,Controller
將無法在 view.fxml
檔案中連結該元件。
看下面的塊有一個清晰的理解。
在控制器
檔案上:
@FXML
Button btnName1
在 FXML 檢視
檔案中:
fx:id="btnName_1"
以下是這兩個原因的解決方案。
JavaFX FXML 載入異常的解決方法
要執行此應用程式,我們使用 Java 18、JavaFX 13 和 NetBeans IDE 版本 13。你可以根據自己的選擇使用所有這些。
示例程式碼(view.fxml
檔案,檢視檔案):
<!--Step1: XML declaration-->
<?xml version="1.0" encoding="UTF-8"?>
<!--Step 2: import necessary java types in FXML-->
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<!--Step 3: specify the FXML namespace-->
<AnchorPane prefHeight="300.0" prefWidth="400.0"
xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mycompany.javafx_fxml_loadexception.viewController">
<!--Step 4: layout pane have children-->
<children>
<Button fx:id="btTest" layoutX="170.0"
layoutY="208.0" mnemonicParsing="false"
onAction="#onBtTestAction" text="Button" />
<Label layoutX="167.0" layoutY="126.0" text="Cick here!" />
</children>
</AnchorPane>
以下是上述程式碼的分步說明。
-
我們通過描述版本和編碼來編寫 XML 宣告。
-
在 FXML 中匯入所有必需的 Java 型別。
-
我們使用
AnchorPane
標籤來宣告fx
名稱空間字首。此標籤允許將子節點的邊緣錨定到距錨窗格邊緣的偏移量。如果錨窗格中有填充或邊框,則將從這些插圖的內邊緣測量偏移量。
AnchorPane
標籤具有下面列出的各種屬性,並附有簡要說明。prefHeight
和prefWidth
屬性可用於覆蓋區域計算的首選高度和寬度。- 在 FXML 中,
fx:controller
用於在root
元素上指定控制器。請記住,我們允許每個 FXML 文件有一個控制器,並且必須在root
元素上指定。
這段程式碼中的
root
元素是什麼?AchnorPane
標記是此程式碼示例的root
元素,它是 FXML 文件的物件圖中的頂級物件。所有 UI 元素都將新增到此元素中。此外,我們還需要知道控制器必須滿足的規則;這些規則如下:
- 控制器由
FXML
載入器例項化。 - 控制器必須具有公共
no-args
建構函式。FXML
載入器如果不存在,將無法例項化它,從而導致載入時出現異常。 - 控制器可以包含可訪問的函式,這些函式也可以在 FXML 中指定為事件處理程式。
FXML
控制器自動查詢控制器的可訪問例項變數。如果可訪問例項變數的名稱與元素的fx:id
屬性匹配,則來自 FXML 的物件引用將自動複製到控制器例項變數中。
此功能將使控制器可以訪問 FXML 中的 UI 元素引用。然後,控制器將能夠使用它們。
- 控制器還可以訪問
initialize()
函式,該函式不能接受引數並返回void
型別。一旦 FXML 文件的載入過程完成,FXML
載入器將呼叫initialize()
函式。
-
在 FXML 中,佈局窗格包含子元素作為它們的子元素。考慮到專案需求,我們可以新增標籤、按鈕和其他元素。
示例程式碼(viewController.java
類,控制器類):
// Step 1: replace this package name with your package name
package com.mycompany.javafx_fxml_loadexception;
// Step 2: import necessary libraries
import javafx.fxml.FXML;
import javafx.scene.control.Button;
// Step 3: viewController class
public class viewController {
// define button
@FXML private Button btTest;
// define the action when the button is clicked
@FXML
public void onBtTestAction() {
System.out.println("CLICK");
} // end onBtTestAction method
} // end viewController class
viewController.java
類是一個控制器類,它在某些成員上使用 @FXML
註釋。請記住,此註解可用於建構函式和類。
使用此註釋,我們指定 FXML
載入器可以輕鬆訪問此成員,即使該成員是 private
。如果 FXML
載入器使用 public
成員,我們不需要使用 @FXML
註釋。
但是,對 public
成員使用 @FXML
不會引發任何錯誤。因此,最好對每個成員進行註釋。
以下 FXML
將控制器類的 onBtTestAction()
函式設定為 Button
的事件處理程式:
<Button fx:id="btTest" layoutX="170.0" layoutY="208.0" mnemonicParsing="false" onAction="#onBtTestAction" text="Button" />
示例程式碼(App.java
類,主類):
// Step 1: replace the package name with your package name
package com.mycompany.javafx_fxml_loadexception;
// Step 2: import necessary libraries
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
// Step 3: primary launch class extending the Application class
public class App extends Application {
/**
*
* @param stage
*/
@Override
public void start(Stage stage) {
// load the view.fxml file, add it to the scene and show it
try {
Parent parent = FXMLLoader.load(getClass().getResource("/fxml/view.fxml"));
// create a scene
Scene scene = new Scene(parent);
// set scene to a stage
stage.setScene(scene);
// show the stage
stage.show();
} // end try
catch (IOException e) {
e.printStackTrace();
} // end catch
} // end start method
public static void main(String[] args) {
launch(args);
} // end main method
} // end App class
主檔案擴充套件
了 Application
類並覆蓋了它的抽象方法 start()
。在 start()
方法中,我們載入 view.fxml
檔案,建立場景,將此場景設定為舞臺,並顯示該舞臺。
輸出(當我們點選按鈕
時,在 IDE 的控制檯上列印單詞 CLICK
):
檢查以下螢幕截圖以將每個檔案放置在正確的位置: