资源文件夹中的 JavaFX 图像

Roy*_*ris 3 java javafx

出于某种原因,我一直在 gradle javafx 项目中获得 NPE。

我的文件夹结构非常基本。我的main/java文件夹中有一个包含我的 java 文件的包。我的main/resources文件夹中也有我的资源。当我尝试加载image.png它时,它给了我一个 NPE。

public static Image createImage(Object context, String url) {
    Image m = null;
    InputStream str = null;
    URL _url = context.getClass().getResource(url);

    try {
        m = new Image(_url.getPath());
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    return m;
}
Run Code Online (Sandbox Code Playgroud)

这是一个辅助类。

SceneI 调用:Image image = Helper.createImage(this, "image.png"); 图像的绝对路径将是main/resources/images/image.png.

我检查了互联网上的每个教程,但找不到任何解决方案。我还尝试将图像路径作为参数,也尝试使用 ,InputStream但它从未奏效。

Sla*_*law 6

资源

Class#getResource(String)和相关的API被用于定位相对于类路径和/或模块路径的资源。当使用Class来获取资源,你可以传递一个绝对的名称或相对名称。绝对名称将相对于类路径/模块路径的根定位资源;绝对名称以/. 相对名称将相对于 的位置定位资源Class;相对名称不以前导/.

在一个典型的Maven /摇篮项目的结构,src/main/java并且src/main/resources类路径/模块路径的。这意味着所有资源名称都与这些目录相关。它略多于复杂,因为在这些目录中的文件移动到目标/ build目录和它的是我们把类路径/模块路径上的位置,但对于所有意图和目的考虑的源目录为根。获取资源 API 的存在首先是有原因的,它提供了一种与应用程序位置无关的获取资源的方式。


代码中的问题

从你的问题我收集你的项目结构看起来像:

<project-dir>
|--src/
   |--main/
      |--java/
      |--resources/
         |--images/
            |--image.png
Run Code Online (Sandbox Code Playgroud)

并且您正在使用Object和 资源名称调用您的方法image.png。这里的问题是,由于您传递的是相对名称,因此资源的位置相对于Class传递的名称Object(即context)。我怀疑您的类位于名为的包中images,这意味着不会找到相对于所述类的资源。您需要传递一个绝对名称:/images/image.png.

另一个问题是您使用URL#getPath(). 在URL你获得Class#getResource(String)的意志,如果资源都可以看到,是这个样子:

file:/path/to/gradle/project/build/resources/main/images/image.png
Run Code Online (Sandbox Code Playgroud)

但结果URL#getPath()会给你:

/path/to/gradle/project/build/resources/main/images/image.png
Run Code Online (Sandbox Code Playgroud)

由于Image工作方式,这会导致问题。从文档

支持的所有 URLURL都可以传递给构造函数。如果传递的字符串不是有效的 URL,而是路径,则在这种情况下在类路径上搜索图像。

注意第二句。如果传递的 URL 没有方案,则将其解释为资源名称Image并将相对于类路径定位图像文件。换句话说,因为你的价值传递URL#getPath()Image构造其搜索资源image.png path.to.gradle.project.build.resources.main.images。那个包不存在。你应该通过URL作为,是对Image通过构造函数URL#toString()URL#toExternalForm()


解决方案

如果您打算使用URL返回的 byClass#getResource(String)来加载 ,Image那么无论您需要使用什么URL#toString()URL#toExternalForm()代替URL#getPath().

public static Image createImage(Object context, String resourceName) {
  URL _url = context.getClass().getResource(resourceName);
  return new Image(_url.toExternalForm());
}
Run Code Online (Sandbox Code Playgroud)

那么你至少有两个选择:

  1. 将绝对资源名称 (ie "/images/image.png") 传递给您的#createImage(Object,String)方法,因为image.png资源与传递的Object(ie context)不在同一个包中。

  2. 将资源移动到与传入的类相同的包Object(即context)。例如,如果上下文对象的类com.foo.MyObject然后将资源放在下面src/main/resources/com/foo,它将与MyObject. 这将允许您继续传递相关资源名称。

当然,正如Image您的文档所指出的,您可以传递无方案的 URL,并将其解释为资源名称。换句话说,你可以这样做:

Image image = new Image("images/image.png");
Run Code Online (Sandbox Code Playgroud)

这应该有效。但是,请注意:当使用模块时,只有当包含资源的包是opens 无条件的或者模块本身是open.