我只是下载了 JavaFX 并进行了设置,我没有做任何其他事情。我运行了示例代码,尽管所有内容都已编译,但还是弹出了警告。我正在使用 IntelliJ。
这是在 Main.java 中:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
这是在sample.fxml中:
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
</GridPane>
Run Code Online (Sandbox Code Playgroud)
运行时,一切都会编译,会弹出窗口,但我收到标题中所述的警告。
我以前从未使用过 JavaFX,所以我不确定在哪里可以找到这个模块。
Sla*_*law 54
长话短说:
确保 JavaFX 被解析为命名模块。
非模块化应用:
java --module-path <path-to-fx> --add-modules <fx-modules> ...
Run Code Online (Sandbox Code Playgroud)
模块化应用:
java --module-path <path> --module <main-module>/<main-class> [args...]
Run Code Online (Sandbox Code Playgroud)
其中<path>包括您的模块以及 JavaFX。
使用包含 JavaFX 的 JDK 发行版(有关更多信息,请参阅下面的答案)。可能还是需要用--add-modules。
或者,如果您决定接受不受支持的配置,则可以忽略该警告。据我所知,从 JavaFX 21 开始,目前没有任何问题。
此警告与 Java 9 中引入的Java 平台模块系统(JPMS)相关。如果您不熟悉模块,那么我建议阅读了解 Java 9 模块以获取简要概述。
JPMS 带来了模块路径,它现在与类路径一起存在。当从类路径加载类时,它们成为所谓的未命名模块的一部分。而模块路径上的类包含在模块中,因此被加载“到”命名的模块中。命名模块可能是自动的,也可能不是自动module-info的,分别取决于它是否有描述符。
JavaFX 仅支持作为命名模块加载。换句话说,JavaFX 仅支持从模块路径加载,而不支持从类路径加载。从版本 9 开始,即框架模块化时,这一点就隐含地成立了。但现在,从版本 16 开始,如果 JavaFX 检测到它是从类路径加载的(即位于未命名模块中),则会发出警告。请参阅JDK-8256362。
解决方案是确保从模块路径加载 JavaFX 并将其解析为命名模块。注意 JavaFX 由七个模块组成,从其文档可以看出。
如何确保 JavaFX 被解析为命名模块可能取决于您的环境(例如,非模块化与模块化应用程序、外部 JavaFX SDK 等)。下面的示例均使用命令行来展示如何设置所需的参数。但是,如果您使用 IDE(例如 NetBeans、IntelliJ、Eclipse)和/或构建工具(例如 Maven、Gradle)并且不确定在哪里设置这些参数,请查看JavaFX 11+ 入门。
请注意,Gradle 和 Maven 都有插件,可以更轻松地使用 JavaFX(即它们为您处理所有配置)。
如果您的代码是非模块化的,那么您就没有module-info描述符。这意味着将 JavaFX 添加到模块路径是不够的;您还必须强制 Java 解析 JavaFX 模块。这可以通过论证来完成--add-modules。
例如:
java --module-path <path-to-fx> --add-modules javafx.controls ...
Run Code Online (Sandbox Code Playgroud)
javafx.controls请注意,我只在参数中包含模块--add-modules。这是因为它需要javafx.base和javafx.graphics模块,这意味着它们将被隐式拉入。
如果您需要其他模块,那么您还需要将它们包含在--add-modules参数中,并用逗号分隔。
另外,请注意,在这种情况下,可以将代码和其他非模块化依赖项放在类路径上。重要的部分是 JavaFX 是从模块路径加载的。
如果您的代码是模块化的,那么您将拥有一个module-info描述符。该描述符将具有必要的requires指令。在这种情况下,您不再需要使用--add-modules,但您确实需要确保通过 来将应用程序作为模块启动--module。
例如:
module app {
// transitively requires javafx.base and javafx.graphics
requires javafx.controls;
// export javafx.application.Application implementation's package
// to at least javafx.graphics
exports com.example.app to javafx.graphics;
}
Run Code Online (Sandbox Code Playgroud)
java --module-path <path> --module app/com.example.app.Main [args...]
Run Code Online (Sandbox Code Playgroud)
请注意,您不仅需要将 JavaFX 放在模块路径上,还需要将您自己的模块放在模块路径上。
从 Java 11 开始,JavaFX 不再包含在 Oracle 提供的 JDK 中。但 Oracle 并不是唯一一家基于 OpenJDK 的 Java 供应商。有些供应商提供包含 JavaFX 的 JDK 发行版。其中至少有两个是:
另请注意,您可以使用jilnk它来创建包含 JavaFX 模块的 Java 运行时。
当 JavaFX 包含在 JDK 中时,它现在像所有其他 Java 模块一样成为运行时映像的一部分(例如java.base)。这意味着它将自动作为命名模块加载,您不再需要手动将 JavaFX 放在模块路径上。
据我所知,如果从类路径加载 JavaFX(从版本 21 开始),目前不会出现任何问题。这意味着至少现在,另一种选择是忽略警告。尽管由于这种配置而造成的任何问题都不太可能被 JavaFX 开发人员修复。
不过,我建议至少将 JavaFX 放在模块路径上(如果您可以轻松做到这一点)。
请注意,当从未命名模块(即类路径)加载 JavaFX 时,主类不能是javafx.application.Application. 您必须定义一个单独的主类,其 main 方法仅启动 JavaFX 应用程序。对于 JavaFX 9 至 JavaFX 21(至少包括 JavaFX 21)都是如此。
以上内容在开发过程中主要有帮助。那么部署呢?如何将 JavaFX 包含在您的应用程序中并从模块路径加载 JavaFX?
请注意,本节仅旨在列出一些部署选项。它没有提供细节。互联网上有许多现有资源可以获取更多信息。有关一些链接,请参阅JavaFX 标签信息页面的“打包”部分。
这与之前的“使用包含 JavaFX 的 JDK 发行版”本质上相同。但是,客户端不应安装 JDK,而应只安装 JRE。请注意,JDK 只是 JRE,但包含开发工具。
除非您控制客户端计算机,否则这种方法可能不切实际。
自包含的应用程序包括您的应用程序代码、所有库代码和 JRE 本身。这意味着客户端甚至不需要安装 Java。
创建独立应用程序的一种方法是通过jlink和/或jpackage(用户指南)。请注意,jlink仅适用于非自动模块,而jpackage可以与非模块化应用程序一起使用,也可以与模块化和非模块化依赖项的混合一起使用(例如,将 JavaFX 放在模块路径上,但将其他所有内容放在类上) -小路)。然而,与 不同的是jlink,该jpackage工具不支持跨平台编译。
另一个选择是GraalVM 的原生镜像。
历史上,Java 应用程序作为可执行 JAR 文件进行分发。所谓的“fat”、“uber”或“shadowed”JAR 文件只是将应用程序中嵌入的所有依赖项嵌入到同一个 JAR 文件中。您可以使用此方法将 JavaFX 透明地包含在您的应用程序中。请注意,这需要客户端安装适当版本的 Java。
使用这种方法是隐式不支持的。JAR文件规范不支持每个 JAR 文件有多个模块,也没有定义任何指定模块路径的方法。此外,可执行 JAR 通常是通过-jar将所有内容都放在类路径上的开关启动的。所有这一切都意味着 JavaFX 将从未命名的模块中加载。简而言之,这种方式本质上是“忽略警告”的部署解决方案。
关于主类的相同规定也适用于此,就像前面的“忽略警告”部分一样。