JavaFX警告:不支持的JavaFX配置:已从“未命名模块@...”加载类

6ioyuze2  于 2023-06-20  发布在  Java
关注(0)|答案(1)|浏览(354)

我只是下载了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);
    }
}

这在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>

运行时,一切编译,窗口弹出,但我得到的警告,如标题所述。
我以前从未使用过JavaFX,所以我不确定在哪里可以找到这个模块。

s4n0splo

s4n0splo1#

    • TL; DR:**

确保JavaFX被解析为 * named modules *。

  • 非模块化应用:
java --module-path <path-to-fx> --add-modules <fx-modules> ...
  • 模块化应用:
java --module-path <path> --module <main-module>/<main-class> [args...]

其中<path>包括您的模块以及JavaFX。

  • 使用包含JavaFX的JDK发行版(请参阅下面的答案以获取更多信息)。可能仍然需要使用--add-modules

后台

此警告与Java 9中引入的 * Java平台模块系统 *(JPMS)有关。如果您不熟悉模块,那么我建议您阅读Understanding Java 9 Modules以获得简要概述。
随着JPMS而来的是模块路径,它现在与类路径并存。当类从类路径加载时,它们成为所谓的“未命名模块”的一部分。而module-path上的类包含在modules中,因此被加载到 * named modules * 中。一个命名模块可能是自动的,也可能不是自动的,这取决于它是否有module-info描述符。

警告

JavaFX只支持作为 * named modules * 加载。换句话说,JavaFX只支持从模块路径而不是类路径加载。从版本9开始,当框架被模块化时,这已经是隐含的事实。但是现在,从版本16开始,如果JavaFX检测到它是从类路径加载的(即在 * 未命名模块 * 中)。参见JDK-8256362

解决方案

解决方案是确保JavaFX从模块路径加载并解析为 * named modules *。注意JavaFX由七个模块组成,如its documentation所示。
如何确保JavaFX被解析为命名模块可能取决于您的环境(例如:非模块化与模块化应用程序、外部JavaFX SDK等)。下面的示例都使用命令行来展示如何设置所需的参数。但是,如果您使用IDE(例如NetBeans、IntelliJ、Eclipse)和/或构建工具(例如,Maven、Gradle),并且不确定在哪里设置这些参数,那么请查看Getting Started with JavaFX 11+
请注意,Gradle和Maven都有插件,可以更轻松地使用JavaFX(即他们为您处理所有配置)。

非模块化应用

如果你的代码是非模块化的,那么你就没有module-info描述符。这意味着将JavaFX添加到模块路径是不够的;你还必须强制Java解析JavaFX模块。这可以通过--add-modules参数来完成。
例如:

java --module-path <path-to-fx> --add-modules javafx.controls ...

注意,我只在--add-modules参数中包含了javafx.controls模块。这是因为它需要javafx.basejavafx.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;
}
java --module-path <path> --module app/com.example.app.Main [args...]

请注意,您不仅需要将JavaFX放在module-path上,还需要将您自己的模块放在module-path上。

使用包含JavaFX的JDK发行版

自Java 11以来,JavaFX不再包含在Oracle提供的JDK中。但Oracle并不是唯一一家基于OpenJDK的Java供应商。有些供应商提供包含JavaFX的JDK发行版。其中至少有两个是:

也可以使用use jilnk to create a Java runtime that includes the JavaFX modules
当JavaFX包含在JDK中时,它现在是运行时映像的一部分,就像所有其他Java模块一样(例如java.base)。这意味着它将自动加载为 * named modules *,您不再需要手动将JavaFX放在module-path上。但是,如果您的应用程序是非模块化的,那么您可能仍然需要使用--add-modules(不确定)。

部署

在部署JavaFX应用程序时,在运行时映像中包含JavaFX可能是最简单的方法。您可以使用jlink/jpackage工具完成此操作。这可以通过包含JavaFX的JDK或外部JavaFX SDK来完成。但是,如果您使用后者,那么请确保在制作自定义运行时映像时使用JMOD文件(或者使用Maven Central的JavaFX JAR,它嵌入了所需的本机代码)。
如果你的代码是非模块化的,那么你需要创建一个自定义的运行时映像,其中包括JavaFX(以及你的应用程序所需的所有其他非自动命名模块),然后配置jpackage将你的代码(以及所有非模块化依赖项)放在类路径上。

忽略警告

据我所知,如果从类路径加载JavaFX,当前没有任何中断。这意味着另一种选择,至少现在,是忽略警告。但是,我建议至少将JavaFX放在模块路径上,如果这样做不会太麻烦的话。

相关问题