JAVAFX:位置未设置错误

5

我的项目在eclipse中正常运行,但是当我创建这个项目的jar文件并尝试通过cmd运行它时,它会显示“位置未设置”错误。

我的项目结构如下:

这是我的项目结构

方法是(在eclipse中运行):

@FXML
private void RegularCustomer(ActionEvent event) throws Exception{
    Stage stage = (Stage) dailySales.getScene().getWindow();
    Scene scene = dailySales.getScene();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("../customer/CustomerHome.fxml"));
    System.out.println(loader.getLocation());
    scene.setRoot(loader.load());
    stage.setScene(scene);
    stage.show();
}

这段代码有什么问题?

有一些相关的问题,但它们与此不同。他们的代码在IDE中无法运行,但我的代码可以在IDE中运行。

顺便说一下:我对文件夹结构进行了一些更改,并成功运行了代码。但那个结构很糟糕,因为我把所有的FXML文件和控制器放在同一个包中。


4
@jewelsea 承认在SO/javafx上有数十个类似的问题(但我在搜索时从未找到它们),但那个问题的答案都没有解决这里确切的问题(我会简要概括为“为什么这个可以用文件系统类加载器但不能用jar类加载器”,我认为这与https://dev59.com/82nWa4cB1Zd3GeqP6P5x更接近)。有人应该撰写一个通用的“如何在JavaFX中加载资源”的问答,因为它似乎引起了很多问题... - James_D
2个回答

15
当您使用getClass().getResource(...)时,您正在加载资源,而不是指定文件路径。在类加载器从文件系统加载类的情况下,它们基本上等同于相同的事情,并且实际上确实有效(尽管即使在这种情况下也没有技术原因)。当类加载器通过其他机制加载类时(并且可能在所有情况下都是如此),则重要的是注意Java资源规范
特别是,请注意:

资源、名称和上下文

资源由由斜杠(/)分隔的一系列子字符串组成的字符串标识,后跟资源名称。每个子字符串必须是有效的Java标识符。资源名称的格式为shortName或shortName.extension。shortName和extension都必须是Java标识符。

(我强调一下)。由于..不是有效的Java标识符,因此无法保证该资源可解析。发生这种情况是因为文件系统类加载器按照您期望的方式解析了这个问题,在IDE中可以正常工作,但是在jar类加载器中实现getResource(...)的方式并不是您所希望的方式。
尝试一下:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/sm/customer/CustomerHome.fxml"));

使用控制器位置加载FXML:

如果您将每个FXML与其相应的控制器文件放在同一个包中(我认为这是一种明智的做法),那么您还可以利用此方法来加载FXML:只需“相对于其控制器”加载FXML:

FXMLLoader loader = new FXMLLoader(CustomerHomeCtrl.class.getResource("CustomerHome.fxml"));

在这种设置中,这似乎相当自然,编译器会检查你在导入该类时是否正确使用了 CustomerHomeCtrl 的包名。这也使得重构变得容易:例如,假设您想将 sm.admin 拆分为多个子包。在 Eclipse 中,您可以创建子包,将 FXML 和控制器拖放到适当的子包中,导入语句将自动更新:不需要进行其他更改。如果路径是在 getResource(...) 中指定的情况下,则所有这些都必须手动更改。

为什么这样说没有多大意义呢?相对路径是相对于类的包。 - Puce
感谢您提供这个绝妙的解决方案。现在它已经完美地运行了。 - Shihab
@Puce 更新了答案并更加精确。如果这样更有意义,我们很感兴趣。 - James_D
在我看来,真正的问题是您操作的文件系统。本地文件系统支持“..”,而JAR文件系统不支持。 - tomsontom
@tomsontom 我的意思是,资源命名的行为有一个独立于文件系统的规范。只要您的资源名称符合该规范,它就可以在应用程序部署的方式不同的情况下正常工作。(理论上,即使底层文件系统的要求比资源命名规范更严格,也是如此。) - James_D

1
有点晚了,但这可能会帮助到某些人。如果您正在使用IntelliJ,则您的resources文件夹可能没有标记为资源文件夹,其具有以下图标: enter image description here 这是我解决它的方法: enter image description here

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