"Location is required" 加载 FXML 文件时出现异常

"Location is required" exception when loading FXML file

我正在尝试加载 FXML 文件并将其显示为应用程序 window,但出现异常。 FXML 文件由 FXML 场景生成器创建。

这是 class

的代码
public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(FXMLLoader.load(getClass().getResource("sample.fxml")));
        primaryStage.show();
    }
}

和 FXML 文件

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<TitledPane animated="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
            prefHeight="400.0" prefWidth="600.0" text="Pass4D" xmlns:fx="http://javafx.com/fxml/1"
            xmlns="http://javafx.com/javafx/8">
    <content>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
            <children>
                <Button layoutX="211.0" layoutY="134.0" mnemonicParsing="false" prefHeight="33.0" prefWidth="177.0"
                        text="Log in"/>
                <Button layoutX="212.0" layoutY="170.0" mnemonicParsing="false" prefHeight="33.0" prefWidth="175.0"
                        text="Exit"/>
            </children>
        </AnchorPane>
    </content>
</TitledPane>

这是我得到的例外情况

Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication7(LauncherImpl.java:157)
    at com.sun.javafx.application.LauncherImpl$$Lambda/2074407503.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Location is required.
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3201)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3169)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3142)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3118)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3098)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3091)
    at Pass4D.start(Pass4D.java:19)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication13(LauncherImpl.java:821)
    at com.sun.javafx.application.LauncherImpl$$Lambda/317090070.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait6(PlatformImpl.java:323)
    at com.sun.javafx.application.PlatformImpl$$Lambda/1833150059.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null4(PlatformImpl.java:292)
    at com.sun.javafx.application.PlatformImpl$$Lambda/2115863517.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater5(PlatformImpl.java:291)
    at com.sun.javafx.application.PlatformImpl$$Lambda/1436737924.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)

我做错了什么?

p.s。这是项目结构

试试这个来自 oracle 的例子:

 @Override
public void start(Stage stage) throws Exception {
   Parent root = FXMLLoader.load(getClass().getResource("fxml_example.fxml"));

    Scene scene = new Scene(root, 300, 275);

    stage.setTitle("FXML Welcome");
    stage.setScene(scene);
    stage.show();
}

今天已经发过了,再发一次,希望对你有帮助。

这是一个在开发环境、Scene Builder 和打包的 JAR 中工作的解决方案。

文件夹结构:

Main.java:

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {

            FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/RootLayout.fxml"));
            AnchorPane rootLayout = (AnchorPane) loader.load();

            Scene scene = new Scene(rootLayout, 400, 400);
            scene.getStylesheets().add(getClass().getResource("css/application.css").toExternalForm());

            primaryStage.setScene(scene);
            primaryStage.show();

        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

RootLayout.fxml:

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

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

<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.view.RootLayoutController">
   <children>
      <Pane layoutX="0.0" layoutY="0.0" prefHeight="200.0" prefWidth="200.0">
         <children>
            <Button fx:id="sunButton" layoutX="74.0" layoutY="88.0" mnemonicParsing="false" onAction="#handleSunButtonClick" styleClass="sun-button" stylesheets="@../css/toolbar.css" text="Button" />
         </children>
      </Pane>
   </children>
</AnchorPane>

RootLayoutController.java:

package application.view;

import javafx.fxml.FXML;
import javafx.scene.control.Button;

public class RootLayoutController {


    @FXML
    Button sunButton;

    @FXML
    public void handleSunButtonClick() {
        System.out.println( "Button clicked");
    }
}

toolbar.css:

.sun-button {
  -fx-graphic: url('./icons/sun.png');
}

application.css:

.root {
    -fx-background-color:lightgray;
}

sun.png:

这在开发环境和打包 JAR 时都有效(在 Eclipse 中选择 "Extract required libraries into generated JAR")。

屏幕截图(只是一个带有通过 css 加载的图标的按钮)

简短的回答是 getClass().getResource("sample.fxml") returns null 如果在 运行 时间找不到资源 classpath ,而不是当前目录等

所以这取决于您的 IDE 项目设置,如果您使用的是 eclipse,请尝试添加 sample.fxml 驻留在 运行 配置中的文件夹。

一些想法...

  • 试试 getClass().getResource("/sample.fxml")...
  • 尝试将 sample.fxml 移动到资源文件夹中。我不太了解你的 IDE,但我怀疑该文件夹仅用于 .java 文件...这对于 eclipse 中的 gradle 项目来说确实如此 - 资源必须是在 src/main/resources 树中,因为只有它被添加到 运行time 类路径中...

Main.class.getResource 对我有用。我试图从 subclass 而不是 Main class 获取资源。我在那里使用了指向当前 class 的 getClass().getResource()。我的资源目录中没有我的 FXML 文件。

将 MainApp.class 附加到 getClass().getResource("/fxml/Scene.fxml") 。为我工作! 例子: 父根 = FXMLLoader.load(MainApp.class.getClass().getResource("/fxml/Scene.fxml"));

删除 javafx 项目中的“build”文件夹并重建项目。

如果您使用的是 Maven,则可能需要将 fxml 文件移动到您的资源目录。

refactor src/main/java/sample/sample.fxml to src/main/resources/sample/sample.fxml 

对我来说,经过反复试验,唯一可行的方法是像这样添加 getClassLoader()

MyClass.class.getClassLoader().getResource("views/myview.fxml")

布局为:

src
   +main
      +resources
         +views
            +myview.fxml

以下是使用 IntelliJ 时的操作 IDE。
当您使用 getClass().getResource() 时,资源必须位于该资源文件夹中与您正在使用的 class 包名称相对应的目录下的资源文件夹中:

src/main/java/com/foo/MyClass.java
src/main/java/resources/com/foo/MyResource.fxml

MyClass.class.getResource(MyResource.fxml) 会起作用

同样的规则适用于使用 FXMLLoader。
在 IntelliJ 世界中,如果将该资源放入 class 所在的同一文件夹中,将找不到该资源。具有讽刺意味的是,当查看生成的 jar 时,您会发现资源实际上与源代码位于同一 jar 文件夹中。这是因为,仅调试编译后的 java classes 与资源目录中的资源一起移动到目标文件夹中。所以真正发生的只是调试构建过程如何工作的产物。我知道如果您使用的是 Android Studio,它的工作方式会略有不同。您可以将资源放在 java 源文件所在的同一文件夹中,它会找到该资源。我不知道上面的 IDE Roland 使用的是什么,但他使用的 IDE 允许他将资源放置在与 java 源所在的目录相同的目录中。