IntelliJ无法识别使用OpenJDK 11的JavaFX 11

101

我在使用IntellJ时遇到了麻烦,它无法识别JavaFX包。 在一个新的JavaFX项目中,使用OpenJDK 11构建项目时,IntelliJ无法识别JavaFX包。

我已经从Maven仓库导入了openjfx:javafx-base-11

我看了其他的问题,解决方案似乎涉及检查字节码是否在正确的级别(我的是),以及项目语言是否正确(我的是)。

有人有什么想法吗?

pic 1

pic 2

pic 3

编辑:

错误:

enter image description here


1
你需要在你的 module-info.java 文件中引入它的模块。 - Jacob G.
我认为你需要这个工件:https://mvnrepository.com/artifact/org.openjfx/javafx/11 基础版本好像不包含所有内容。 - Jorn Vernee
@JornVernee 当我尝试那样做时,我遇到了一个错误。我已经在原始帖子中进行了编辑。 - AlwaysNeedingHelp
2
谁告诉你的可能是错的。你需要在源文件夹中创建一个 module-info.java 文件,并明确要求您正在使用的任何 JavaFX 模块:requires javafx.controls;requires javafx.graphics;等。 - Jacob G.
@Slaw,感谢您。在我升级Intellij之后,我能够在下拉列表中找到它了。 - iCoder
显示剩余9条评论
7个回答

168

如评论中提到的,起步指南 是开始学习 Java 11 和 JavaFX 11 的地方。

与 Java 11 之前的工作方式相同的关键在于理解:

  • JavaFX 11 不再是 JDK 的一部分了
  • 您可以以不同的形式获得它,作为 SDK 或常规依赖项(maven/gradle)。
  • 即使您的项目不是模块化的,您也需要将其包含到项目的模块路径中。

JavaFX 项目

如果您在 IntelliJ 中创建一个普通的 JavaFX 默认项目(没有 Maven 或 Gradle),我建议您从这里下载 SDK。请注意,也有 jmods,但对于非模块化项目,SDK 更受欢迎。

以下是运行默认项目的简单步骤:

  1. 创建一个JavaFX项目
  2. 设置JDK 11(指向本地Java 11版本)
  3. 将JavaFX 11 SDK添加为库。URL 可能类似于 /Users/<user>/Downloads/javafx-sdk-11/lib/。添加后,您会注意到编辑器中现在已识别出 JavaFX 类。

JavaFX 11 Project

  1. 在运行默认项目之前,您只需要将这些添加到 VM 选项中:

    --module-path /Users/<user>/Downloads/javafx-sdk-11/lib --add-modules=javafx.controls,javafx.fxml

  2. 运行

Maven

如果您使用 Maven 来构建项目,请遵循以下步骤:

  1. 使用 JavaFX 原型创建一个 Maven 项目
  2. 设置JDK 11(指向本地Java 11版本)
  3. 添加 JavaFX 11 依赖项。

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>11</version>
        </dependency>
    </dependencies>
    

一旦你这样做了,你会注意到编辑器现在已经识别出JavaFX类。

JavaFX 11 Maven project

你会发现Maven为你管理所需的依赖关系:它将为javafx.controls添加javafx.base和javafx.graphics,但最重要的是,它将根据你的平台添加所需的分类器。在我的情况下,是Mac平台。

这就是为什么你的org.openjfx:javafx-controls:11 JAR文件是空的,因为有三个可能的分类器(Windows、Linux和Mac平台),它们包含所有的类和本地实现。

如果你仍然想去你的.m2 repo手动获取依赖项,请确保选择正确的依赖项(例如.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-mac.jar

  1. 使用这里的插件替换默认的Maven插件。

  2. 运行mvn compile javafx:run,它应该能够工作。

类似的方法也适用于Gradle项目,详见这里

编辑

提到的入门指南包含了更新的文档和面向IntelliJ的示例项目:


1
路径类似于/Users/<user>/Downloads/javafx-sdk-11/lib/,请注意lib文件夹。它应该包含所有的JavaFX JAR文件。 - José Pereda
9
如果有人在模块路径上遇到问题,需要在Windows中设置为以下格式:--module-path="C:\Path\To\Your\JavaFX\lib" --add-modules=javafx.controls,javafx.fxml,javafx.base,javafx.media,javafx.graphics,javafx.swing,javafx.web请注意等号和引号。这种方法适用于我,而其他任何方法都不行。另外,请记住,在模块路径和add-modules选项之后,-jar YourJar.jar参数需要出现。 - Jalau
4
嗨@JoséPereda。我已经挣扎了一段时间,尝试按照指南操作,但我无法让IntelliJ运行我的代码,即使我已经完全按照你写的做了。我仍然会收到“Error:java: module not found: javafx.fxml”等错误信息。有没有私人聊天的机会来帮助我解决这个问题?谢谢。 - Davide3i
1
@jalau 谢谢!引号确实解决了问题,你应该把它写成一个答案。 - derfect
2
当我为Gradle的示例项目构建分发并运行它时,我收到错误消息:“错误:缺少JavaFX运行时组件,并且需要运行此应用程序”。 - Hakanai
显示剩余9条评论

18

JavaFX不再是JDK 11的一部分的问题。以下解决方案可以在IntelliJ中使用(尚未尝试NetBeans):

  1. 将JavaFX全局库添加为依赖项:

    设置 -> 项目结构 -> 模块。在模块中转到 依赖关系选项卡,单击加号“+”->库-> Java-> 从列表中选择JavaFX并单击添加所选,然后应用设置。

  2. 在您的JavaFX项目中右键单击源文件(src),然后创建一个新的module-info.java文件。在文件中编写以下代码:

    module YourProjectName { 
        requires javafx.fxml;
        requires javafx.controls;
        requires javafx.graphics;
        opens sample;
    }
    

    我向您保证,遵循这2个步骤将解决您在JavaFX方面的所有问题。

参考资料:The Learn Programming频道制作了一个YouTube教程,将在短短5分钟内解释上述所有细节。我还建议观看它来解决您的问题: https://www.youtube.com/watch?v=WtOgoomDewo


8

2020年12月14日更新

Intellij为Idea创建了一个新的JavaFX项目向导

强烈建议,如果您在使用JavaFX项目时遇到问题,那么使用新的JavaFX项目向导

  1. 使用向导创建新项目。
  2. 测试新项目是否可用。
  3. 将旧项目中相关代码复制到新项目中。

新项目向导非常易于使用,可以在不到一分钟的时间内快速启动并运行JavaFX项目。

该向导生成的项目具有以下特点:

  1. 适用于小型应用程序的简单工作示例代码。
  2. 使用JavaFX图形、控件和fxml。
  3. 配置maven或gradle项目以使用JavaFX,并为基本开发提供适当的maven构件依赖项。
  4. 使用较新的、相对最新的JavaFX模块,版本一致(这是许多初学者经常没有做到的)。
  5. 添加适用于基于FXML的JavaFX应用程序的module-info.java文件(如果不使用FXML也有效)。
  6. 演示将FXML文件放置在资源目录中,并在运行时将其作为资源查找(这是许多初学者经常做错的事情)。
  7. 正确地将控制器类与应用程序类分离(这也是许多初学者经常做错的事情)。
  8. 演示了基于FXML文件中ID的@FXML注入的正确使用方法(这也是许多初学者经常做错的事情)。
  9. 不需要openjfx JavaFX SDK下载(因为JavaFX模块依赖项是通过maven获取的)。
  10. 不需要手动设置VM参数来运行应用程序(因为适当的模块语句在module-info.java文件中而不是VM命令行中)。
  11. 允许直接从IDE执行和调试JavaFX应用程序。
  12. 包括openjfx maven插件。
    • 如果您想要,可以忽略它或从生成的项目文件中删除它。

关于openjfx-maven插件的几点想法:

  • 大多数情况下,我认为您不需要使用它。
    • 如果不需要,可以从项目中删除它。
  • 执行应用程序不需要openjfx maven插件。
    • 尽管你可以这样做,但就我所知,它并没有比在IDE中直接执行任何优势。
  • 如果您想要构建基于jlink的分发,则可以使用openjfx maven插件。
  • 至少目前,openjfx maven插件无法使用jpackage打包您的应用程序:

以前的答案:

本前答案中的一些信息仍然有助于理解Java平台模块化和JavaFX的背景信息。

简要总结,您可以执行以下任一操作:

  1. 通过--module-path--add-modules包含JavaFX模块,就像在Jose的答案中那样。

或者

  1. 一旦将JavaFX库添加到您的项目中(手动或通过Maven / Gradle导入),请添加与本答案中指定的类似的module-info.java文件。(请注意,此解决方案使您的应用程序成为模块化,因此如果使用其他库,则还需要在module-info.java文件中添加要求其模块的语句)。

此答案是Jose答案的补充说明。

情况是这样的:

  1. 您正在使用最新的Java版本,例如13。
  2. 您有一个JavaFX应用程序作为Maven项目。
  3. 在Maven项目中,您已配置了JavaFX插件,并设置了JavaFX依赖项,如Jose的答案所述。
  4. 您转到扩展Application的主类的源代码,右键单击它并尝试运行它。
  5. 当尝试启动应用程序时,会出现涉及“未命名模块”的IllegalAccessError

以下是从Intellij Idea运行JavaFX应用程序时生成IllegalAccessError的堆栈跟踪摘录:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
    at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
    at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
    at org.jewelsea.demo.javafx.springboot.Main.start(Main.java:13)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application org.jewelsea.demo.javafx.springboot.Main

好的,现在你有点卡住了,不知道发生了什么。

实际上发生的事情是这样的:

  1. Maven已成功为您的应用程序下载了JavaFX依赖项,因此您不需要单独下载依赖项或安装JavaFX SDK或模块分发等任何内容。
  2. Idea已将模块成功导入项目作为依赖项,因此一切都可以编译,所有代码完成和其他功能都可以正常工作。

所以看起来一切都应该没问题。但是,当您运行应用程序时,JavaFX模块中的代码在尝试使用反射来实例化应用程序类(当您调用launch时)和FXML控制器类(当您加载FXML时)时失败了。如果没有帮助,在某些情况下,这种反射使用可能会失败,从而生成晦涩的IllegalAccessError。这是由于Java模块系统安全功能,它不允许来自其他模块的代码在未显式允许的情况下使用反射访问您的类(并且JavaFX应用程序启动器和FXMLLoader都需要反射才能正确运行)。

这就是其他答案在提到module-info.java时如何解决问题的原因。

因此,让我们快速了解一下Java模块:

关键部分如下:

4.9. Opens

If we need to allow reflection of private types, but we don't want all of our code exposed, we can use the opens directive to expose specific packages.

But remember, this will open the package up to the entire world, so make sure that is what you want:

module my.module { opens com.my.package; }

那么,也许您不想将您的包裹对整个世界开放,那么您可以这样做:

4.10. 开放……给

好吧,反射有时很棒,但我们仍然希望从封装中获得尽可能多的安全性。我们可以通过使用opens…to指令,选择性地向预先批准的模块列表开放我们的包裹,例如:

module my.module { opens com.my.package to moduleOne, moduleTwo, etc.; }

因此,您最终创建了一个src/main/java/module-info.java类,它看起来像这样:

module org.jewelsea.demo.javafx.springboot {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}

其中org.jewelsea.demo.javafx.springboot是包含JavaFX应用程序类和JavaFX控制器类的包名称(将其替换为您的应用程序的适当包名称)。这告诉Java运行时,允许javafx.graphicsjavafx.fxml中的类对您的org.jewelsea.demo.javafx.springboot包中的类进行反射调用。完成此操作后,编译并重新运行应用程序,一切都将正常工作,JavaFX使用反射生成的IllegalAccessError将不再发生。

但是,如果您不想创建module-info.java文件怎么办?

如果您不是直接使用IDE中顶部工具栏中的Run按钮来运行应用程序类,而是:

  1. 转到IDE侧边栏上的Maven窗口。
  2. 选择JavaFX maven插件目标javafx.run
  3. 右键单击它,然后选择Run Maven BuildDebug...

那么应用程序将在没有module-info.java文件的情况下运行。我猜这是因为maven插件足够智能,可以动态包含某些设置,即使没有module-info.java文件,也允许JavaFX类对其进行反射,但我不知道这是如何实现的。

要将该设置传输到顶部工具栏中的Run按钮,请右键单击javafx.run Maven目标,并选择创建运行/调试配置选项。然后,您只需选择从顶部工具栏执行Maven目标即可。


当我这样做时(被org.beryx.jlink替换),我没有看到任何maven插件,因此这个答案可能需要另一个更新,但你是对的,这是IntelliJ最近必须添加的一个很棒的功能。我现在可能会将所有项目转换为这种外观。 - Manius
org.beryx.jlink是Gradle插件,当您使用Idea New JavaFX Project向导并选择Gradle作为构建系统时,它将包含在gradle.build文件中。只有当您选择Maven作为构建系统而不是Gradle时,javafx-maven-plugin才会包含在Maven pom.xml文件中。我建议选择Maven,除非您了解并喜欢Gradle。 - jewelsea
当然,抱歉我有点过于以Gradle为中心,认为整个世界都围绕着Gradle转,甚至没有想到这是使用Maven作为示例。 :) (Gradle项目使用Maven仓库,更加混淆了问题。) - Manius

7

以上方法都不适用于我,我花了太多时间来清理出现的其他错误。我发现这是最简单、最好的方法。

此方式适用于获取Jdk 11、12及OpenJdk12上的JavaFx!

  • 该视频演示了JavaFx Sdk下载的过程
  • 如何将其设置为全局库
  • 设置module-info.java (我更喜欢底部的)

module thisIsTheNameOfYourProject {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens sample;
}

整个过程只花了我5分钟!!!

在2019.3版本中,将其设置为全局库已经移动了。你能指出现在它的位置在哪里吗? - Michael S.
只需将其添加到fx分发的\lib文件夹中。 - WebComer

2

现在是2021年,JetBrains更新了他们的IDE。关于这个错误信息的其他问题已经关闭并指向此处。

Error: JavaFX runtime components are missing, and are required to run this application

如果您已经按照这些答案中的所有其他步骤(例如库、--module-path、--add-modules、JDK和JavaFX版本匹配)进行操作,但仍然看到此编译错误,请确保您的运行/编译配置将 --module-path 和 --add-modules 作为 VM Options 而不是 Program Arguments 在 IntelliJ 中。
以下是操作步骤:
  1. 打开 Run/Debug Configurations
  2. 打开 Modify Options 下拉菜单
  3. 点击 Add VM Options

0
在运行配置中的VM选项中添加此行:
--module-path yourpathwheresdkislocated/lib --add-modules=javafx.controls,javafx.fxml 

如果您想从终端运行您的jar应用程序,请输入以下命令:
java --module-path yourpathwheresdkislocated/lib --add-modules=javafx.controls,javafx.fxml -jar YourJar.jar 

0
可以在这里找到非常好的解释:

https://edencoding.com/runtime-components-error/

包括

  1. 给予模块反射访问权限

  2. 给予其他人访问你的模块的权限

总之,除了上述答案外,我们还需要在你的模块定义中添加 exports

module my.project {
    requires javafx.fxml;
    requires javafx.controls;
    opens my.project to javafx.graphics;
    exports my.project;
}

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