如何在资源文件夹中引用JavaFX的FXML文件?

50
我正在创建一个JavaFX GUI应用程序,我的项目是一个已配置了Maven的项目。我希望能够在我的控制器中像这样引用我的fxml文件:
FXMLLoader.load(getClass().getResource("main.fxml")); 

我的main.fxml文件位于src/main/resources文件夹中,而我的控制器位于src/main/java文件夹中。我应该如何操作?我的src/main/resources文件夹在构建路径中,并且我可以从src/main/java文件夹中的类调用位于src/main/resources文件夹中的.properties文件。
编辑:
我尝试将fxml文件放置在主资源文件夹的相应目录中:

enter image description here

但是我还是遇到了一个错误。
3个回答

125

通用资源查找信息

本文讨论FXML位置查找,实际上它只是Java中通用资源查找任务的一个子集。资源位置由调用程序作为输入传递给FXMLLoader,因此资源查找本身是您的调用应用程序代码的一部分,而不是FXMLLoader的一部分。

对于Java / JavaFX应用程序的通用资源信息(包括推荐的故障排除步骤),请参阅:

Eden编码资源指南也很有用:


示例用法

FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/main.fxml"));
Parent content = loader.load(); 

位置解析选项

  1. Put all of your fxml in the src/main/resources directory.

    loader.setLocation(getClass().getResource("/main.fxml"));
    
  2. Put all of your fxml in a src/main/resources/fxml directory.

    loader.setLocation(getClass().getResource("/fxml/main.fxml"));
    
  3. Place fxml in a corresponding resource directory; e.g. src/main/resources/com/mycompany/myapp.

    loader.setLocation(getClass().getResource("main.fxml")); 
    
最后一种选项假定你正在加载fxml的类与相应的Java源代码层次结构中的位置相对应。例如,您可能会从源com/mycompany/myapp/Main.java调用最后一个加载命令。
FXMLLoader使用建议
  1. 使用 new FXMLLoader() 实例化FXMLLoader,而不是使用 FXMLLoader的静态方法

    • 当您希望从加载器中获取值(如已实例化的控制器)时,静态方法会变得混淆。
  2. 在实例化的FXMLLoader上设置位置并调用load(),而不是使用流从load(stream)进行加载。

    • 在加载fxml和css文件中的相对资源时,将基于URL在加载器上设置位置允许进行解析。 相对资源不适用于基于流的构造函数。
  3. 要基于类派生位置,请使用getClass().getResource(),因为它是基于URL的,而不是getClass().getResourceAsStream(),它是基于流的。

IDE和构建设置

确保您的IDE或构建工具将fxml文件从资源目录复制到构建输出目录。要了解Intellij的设置,请参见:如何将普通Java项目转换为JavaFx项目

关于Java Jigsaw模块化应用的说明

请参见:

具体来说,不要写:

ComboBoxStyling.class.getClassLoader()
    .getResource("/css/styleclass.css");

改为写成:

ComboBoxStyling.class
    .getResource("/css/styleclass.css"); 

也就是说,直接从类中获取资源,而不是从类加载器中获取。如果您从类加载器而不是类中获取资源,则根据模块配置会有额外的查找限制。这些限制可能很难理解,如果需要了解信息,请参阅ClassClassLoadergetResource方法的文档。


你的示例仍在使用静态方法。你需要调用getResourceAsStream而不是getResource。 - Felix S
2
谢谢Felix,已经修复并澄清了答案。在3年和28个赞之后,没有人在原始答案中指出这个异常情况。;-) - jewelsea
1
一直以来,它一直失败是因为我没有在起始文件夹之前加上/,即getClass().getResource("fxml/main.fxml") - olfek
NetBeans用户请注意,您可以通过右键单击项目目录>属性>选择“源”>选择要添加到源的文件夹>添加文件夹来将现有文件夹添加到src中。因此,如果您已经有一个包含您要引用的fxml的文件夹,您只需添加该文件夹并使用其相对路径调用fxml文件即可。 - Eric

7
你正在使用 FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main.fxml")); 加载你的 main.fxml。这需要 main.fxml 和加载它的 java 类在同一个目录/路径下。 如果你想从与加载它的 java 类不同的路径/位置加载 fxml 文件,你需要使用相对路径。 如 @jewelsea 上面提到的,你可以在 main.fxml 前使用 / 字符来使用相对路径。 因此,在你的情况下使其正常工作的代码是:
FXMLLoader fxmlLoader = new FXMLLoader( getClass().getResource("/main.fxml") );

实际上这是问题的简单答案,一旦你思考它就很有道理。路径是相对于我们调用FXMLLoader()的源文件的。 - Ajoy

0

在操作系统的文件浏览器中打开您的资源文件夹。在这里,您会发现您创建了一个名为“dominion.application”的文件夹,而不是在“dominion”文件夹内创建一个名为“application”的文件夹。因此,“MainController”类被放置在与fxml文件不同的包中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接