如何确定我的JavaFX应用程序所需的FXML文件、CSS文件、图像和其他资源的正确路径?

如何确定我的JavaFX应用程序所需的FXML文件、CSS文件、图像和其他资源的正确路径?,javafx,Javafx,我的JavaFX应用程序需要能够找到FXML文件,以便使用FXMLLoader加载它们,以及样式表(CSS文件)和图像。当我尝试加载这些时,经常会出现错误,或者我尝试加载的项在运行时根本无法加载 对于FXML文件,我看到的错误消息包括 原因:java.lang.NullPointerException:未设置位置 对于图像,堆栈跟踪包括 原因:java.lang.IllegalArgumentException:无效URL:无效URL或未找到资源 如何为这些资源找到正确的资源路径?answe

我的JavaFX应用程序需要能够找到FXML文件,以便使用
FXMLLoader
加载它们,以及样式表(CSS文件)和图像。当我尝试加载这些时,经常会出现错误,或者我尝试加载的项在运行时根本无法加载

对于FXML文件,我看到的错误消息包括

原因:java.lang.NullPointerException:未设置位置
对于图像,堆栈跟踪包括

原因:java.lang.IllegalArgumentException:无效URL:无效URL或未找到资源
如何为这些资源找到正确的资源路径?

answer的简短版本:
  • 使用
    getClass()
  • 将绝对路径(带前导的
    /
    )或相对路径(不带前导的
    /
    )传递给
    getResource(…)
    方法。路径是包含资源的包,其中
    替换为
    /
  • 不要在资源路径中使用
    。如果应用程序被捆绑为jar文件,这将不起作用。如果资源不在同一个包或类的子包中,请使用绝对路径
  • 对于FXML文件,将
    URL
    直接传递给
    FXMLLoader
  • 对于图像和样式表,在
    URL
    上调用
    toExternalForm()
    ,生成
    字符串
    ,以传递给
    图像
    图像视图
    构造函数,或添加到
    样式表
    列表中
  • 要进行故障排除,请检查buid文件夹(或jar文件)的内容,而不是源文件夹

完整答案 目录
  • 本答复的范围
  • 资源在运行时加载
  • JavaFX使用URL加载资源
  • 资源名称规则
  • 使用
    getClass().getResource(…)
  • 组织代码和资源
  • Maven(及类似)标准布局
  • 故障排除
  • 本答复的范围 请注意,此答案仅用于加载作为应用程序一部分并与之捆绑的资源(例如FXML文件、图像和样式表)。因此,例如,加载用户从运行应用程序的计算机上的文件系统中选择的图像将需要不同的技术,这里没有介绍这些技术

    资源在运行时加载 关于加载资源,首先要了解的是,它们当然是在运行时加载的。通常,在开发过程中,应用程序是从文件系统运行的:也就是说,运行应用程序所需的类文件和资源是文件系统上的单个文件。然而,一旦构建了应用程序,它通常是从jar文件执行的。在本例中,诸如FXML文件、样式表和图像等资源不再是文件系统中的单个文件,而是jar文件中的条目。因此:

    代码不能使用文件文件输入流文件:URL加载资源

    JavaFX使用URL加载资源 JavaFX使用URL加载FXML、图像和CSS样式表

    fxmloader
    显式要求将
    java.net.URL
    对象传递给它(传递给
    static
    fxmloader.load(…)
    方法、传递给
    fxmloader
    构造函数或传递给
    setLocation()
    方法)

    Image
    Scene.getStylesheets()。添加(…)
    expect
    String
    s表示URL。如果URL是在没有方案的情况下传递的,那么它们将相对于类路径进行解释。通过在
    URL
    上调用
    toExternalForm()
    ,可以从
    URL
    以一种健壮的方式创建这些字符串

    为资源创建正确URL的推荐机制是使用
    Class.getResource(…)
    ,它在适当的
    Class
    实例上调用。这样的类实例可以通过调用
    getClass()
    (给出当前对象的类)或
    ClassName.class
    来获得。
    Class.getResource(…)
    方法采用表示资源名称的
    字符串

    资源名称规则
    • 资源名是
      /
      分隔的路径名。每个组件表示一个包或子包名称组件
    • 资源名称区分大小写
    • 资源名称中的各个组件必须是有效的Java标识符
    最后一点具有重要的后果:

    不是有效的Java标识符,因此它们不能在资源名称中使用

    当应用程序从文件系统运行时,它们实际上可能会起作用,尽管这实际上是
    getResource()
    实现的一个意外。当应用程序绑定为jar文件时,它们将失败

    类似地,如果您运行的操作系统不区分仅按大小写不同的文件名,那么在资源名中使用错误的大小写可能会在从文件系统运行时起作用,但在从jar文件运行时会失败

    以前导
    /
    开头的资源名称是绝对的:换句话说,它们是相对于类路径进行解释的。不带前导的
    /
    的资源名称相对于调用
    getResource()
    的类进行解释

    这方面的一个细微变化是使用
    getClass().getClassLoader().getResource(…)
    。提供给
    ClassLoader.getResource(…)
    的路径始终是绝对的,即它相对于类路径。
     // FXML file in the same package as the current class:
     URL fxmlURL = getClass().getResource("MyFile.fxml");
     Parent root = FXMLLoader.load(fxmlURL);
    
     // FXML file in a subpackage called `fxml`:
     URL fxmlURL2 = getClass().getResource("fxml/MyFile.fxml");
     Parent root2 = FXMLLoader.load(fxmlURL2);
    
     // Similarly for images:
     URL imageURL = getClass().getResource("myimages/image.png");
     Image image = new Image(imageURL.toExternalForm());
    
     URL cssURL = getClass().getResource("/org/jamesd/examples/css/style.css");
     scene.getStylesheets().add(cssURL.toExternalForm());
    
    FXMLLoader editorLoader = new FXMLLoader(EditorController.class.getResource("Editor.fxml"));
    Parent editor = editorLoader.load();
    FXMLLoader sidebarLoader = new FXMLLoader(SidebarController.class.getResource("Sidebar.fxml"));
    Parent sidebar = sidebarLoader.load();
    
    ImageView logo = new ImageView();
    logo.setImage(newImage(SidebarController.class.getResource("logo.png").toExternalForm()));
    
    mainScene.getStylesheets().add(App.class.getResource("style.css").toExternalForm());
    
    package org.jamesd.examples.sample.images ;
    public interface ImageLocation { }
    
    Image clubs = new Image(ImageLocation.class.getResource("clubs.png").toExternalForm());
    
    package org.jamesd.examples.resourcedemo;
    
    import java.net.URL;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception {        
            
            URL fxmlResource = getClass().getResource("fxml/MainView.fxml");
            
            
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(fxmlResource);
            Parent root = loader.load();
            Scene scene = new Scene(root);
            scene.getStylesheets().add(getClass().getResource("style/main-style.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        
        public static void main(String[] args) {
            Application.launch(args);
        }
    
    }
    
        URL fxmlResource = getClass().getResource("/org/jamesd/examples/resourcedemo/fxml/MainView.fxml");