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
):
检查以下屏幕截图以将每个文件放置在正确的位置: