如评论中提到的,起步指南 是开始学习 Java 11 和 JavaFX 11 的地方。
与 Java 11 之前的工作方式相同的关键在于理解:
JavaFX 项目
如果您在 IntelliJ 中创建一个普通的 JavaFX 默认项目(没有 Maven 或 Gradle),我建议您从这里下载 SDK。请注意,也有 jmods,但对于非模块化项目,SDK 更受欢迎。
以下是运行默认项目的简单步骤:
/Users/<user>/Downloads/javafx-sdk-11/lib/
。添加后,您会注意到编辑器中现在已识别出 JavaFX 类。在运行默认项目之前,您只需要将这些添加到 VM 选项中:
--module-path /Users/<user>/Downloads/javafx-sdk-11/lib --add-modules=javafx.controls,javafx.fxml
运行
Maven
如果您使用 Maven 来构建项目,请遵循以下步骤:
添加 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类。
你会发现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
)
使用这里的插件替换默认的Maven插件。
运行mvn compile javafx:run
,它应该能够工作。
类似的方法也适用于Gradle项目,详见这里。
编辑
提到的入门指南包含了更新的文档和面向IntelliJ的示例项目:
/Users/<user>/Downloads/javafx-sdk-11/lib/
,请注意lib
文件夹。它应该包含所有的JavaFX JAR文件。 - José PeredaJavaFX不再是JDK 11的一部分的问题。以下解决方案可以在IntelliJ中使用(尚未尝试NetBeans):
将JavaFX全局库添加为依赖项:
设置 -> 项目结构 -> 模块。在模块中转到 依赖关系选项卡,单击加号“+”->库-> Java-> 从列表中选择JavaFX并单击添加所选,然后应用设置。
在您的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
2020年12月14日更新
Intellij为Idea创建了一个新的JavaFX项目向导。
我强烈建议,如果您在使用JavaFX项目时遇到问题,那么使用新的JavaFX项目向导:
新项目向导非常易于使用,可以在不到一分钟的时间内快速启动并运行JavaFX项目。
该向导生成的项目具有以下特点:
关于openjfx-maven插件的几点想法:
jpackage
打包您的应用程序:以前的答案:
本前答案中的一些信息仍然有助于理解Java平台模块化和JavaFX的背景信息。
简要总结,您可以执行以下任一操作:
--module-path
和--add-modules
包含JavaFX模块,就像在Jose的答案中那样。或者
module-info.java
文件。(请注意,此解决方案使您的应用程序成为模块化,因此如果使用其他库,则还需要在module-info.java
文件中添加要求其模块的语句)。此答案是Jose答案的补充说明。
情况是这样的:
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
好的,现在你有点卡住了,不知道发生了什么。
实际上发生的事情是这样的:
所以看起来一切都应该没问题。但是,当您运行应用程序时,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.graphics
和javafx.fxml
中的类对您的org.jewelsea.demo.javafx.springboot
包中的类进行反射调用。完成此操作后,编译并重新运行应用程序,一切都将正常工作,JavaFX使用反射生成的IllegalAccessError
将不再发生。
但是,如果您不想创建module-info.java文件怎么办?
如果您不是直接使用IDE中顶部工具栏中的Run按钮来运行应用程序类,而是:
javafx.run
。Run Maven Build
或Debug...
。那么应用程序将在没有module-info.java
文件的情况下运行。我猜这是因为maven插件足够智能,可以动态包含某些设置,即使没有module-info.java
文件,也允许JavaFX类对其进行反射,但我不知道这是如何实现的。
要将该设置传输到顶部工具栏中的Run按钮,请右键单击javafx.run
Maven目标,并选择创建运行/调试配置选项。然后,您只需选择从顶部工具栏执行Maven目标即可。
以上方法都不适用于我,我花了太多时间来清理出现的其他错误。我发现这是最简单、最好的方法。
此方式适用于获取Jdk 11、12及OpenJdk12上的JavaFx!
module thisIsTheNameOfYourProject {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
opens sample;
}
现在是2021年,JetBrains更新了他们的IDE。关于这个错误信息的其他问题已经关闭并指向此处。
Error: JavaFX runtime components are missing, and are required to run this application
--module-path yourpathwheresdkislocated/lib --add-modules=javafx.controls,javafx.fxml
java --module-path yourpathwheresdkislocated/lib --add-modules=javafx.controls,javafx.fxml -jar YourJar.jar
https://edencoding.com/runtime-components-error/
包括
给予模块反射访问权限
给予其他人访问你的模块的权限
总之,除了上述答案外,我们还需要在你的模块定义中添加 exports。
module my.project {
requires javafx.fxml;
requires javafx.controls;
opens my.project to javafx.graphics;
exports my.project;
}
module-info.java
文件中引入它的模块。 - Jacob G.module-info.java
文件,并明确要求您正在使用的任何 JavaFX 模块:requires javafx.controls;
,requires javafx.graphics;
等。 - Jacob G.