如何使用 Java15 将 JavaFX 15 代码部署到 JAR

How to deploy JavaFX 15 Code to JAR with Java 15

我在将 JavaFX 项目部署到 .jar 或 .exe 文件以轻松执行它(并达到项目要求)时遇到问题。 我试图让它作为 .jar 文件工作,因为我认为这是更简单的方法,但也许我错了所以如果你能帮助我解决这个问题那就太棒了。

我已经尝试使用 Intellij 的 Artifacts,但这不起作用。我收到一条错误消息,上面写着“错误:JavaFX 运行时间组件丢失,并且需要 运行 此应用程序”。 然后我尝试使用我在 Internet 上找到的另一种方式:https://github.com/openjfx/samples/tree/master/CommandLine/Non-modular/CLI 但这在尝试将其打包到 .jar 文件时会产生完全相同的消息。

以上所有我都在我现有的项目和一个全新的项目上尝试过,当你创建一个新的 JavaFX 项目时,除了来自 Intellij 的 prewirtten Stuff 什么都没有。

我的项目与 Maven 或 Gradle 完全不同,我只有一个基本的 JavaFX 项目(JavaFX 15 和 Java 15)以及一个附加项目库:org.json:json 版本 20201115

我希望这些信息足以让您了解我的问题并希望对我有所帮助,但如果不是,请询问您需要什么,我会尽力提供给您。

感谢您的帮助:)

此致

马克西

编辑:与下方评论相关的错误消息

Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:280)
        at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:244)
        at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:261)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        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:64)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:94)
        at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
        at java.base/java.lang.Thread.run(Thread.java:832)
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: No toolkit found
        at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:273)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
        ... 5 more

这可能与您的具体情况无关,但也许可以给您一些提示。

简短说明

我解决了 "Error initializing QuantumRenderer: no suitable pipeline found" 在 Gradle 的帮助下,通过手动将库文件包含到胖 JAR 并将它们添加到用于执行的 class 路径 。 包括我:
  • 我系统的 openJFX 安装所需的 openJFX-JARs
  • 随附的 C++ 库,如渲染器 libprism_sw.so(*.so on linux,*. Windows)
  • 上的 dll

库的提示来自 JavaFX on Linux is showing a "Graphics Device initialization failed for : es2, sw"

  • “问题可能出在您的旧 JRE 版本中,它不包含所有必需的库,例如 libprism_es2.so 或 libglass.so,它们应该位于 /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64 ."
  • ...
  • “从 Oracle 官方网站下载最新的 JRE,并将 lib 文件夹复制到您当前的 JRE 位置。这应该足够了。”

完整解释

"Error initializing QuantumRenderer" 问题

我遇到了一个类似的问题,一个胖 JAR 充满了来自 code for a Java-book 的几个 JFX-example classes。该项目使用 Gradle 进行构建管理,运行 使用胖 JAR (build/libs/Java-Profi-all.jar) 的 JFX 示例。

当我尝试在命令行上使用 [=71] 为 JFX (FirstJavaFxExample) 执行一个简单的 HelloWorld 示例时出现“Error initializing QuantumRenderer” =]bin/java 我当前的 JRE,而不使用 Gradle。我几乎用 JavaFX on Linux is showing a "Graphics Device initialization failed for : es2, sw" 上的提示解决了这个问题,但最后我陷入了同样的错误。即使我在胖 JAR 中添加了所需的 openJFX-JAR 和随附的 C++ 库,并通过“-cp ...:[=​​137=]”添加到 class 路径。

使用的命令:

/usr/lib64/jvm/java-1.8.0-openjdk-1.8.0/bin/java -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -Dprism.verbose=true -cp projectdir/build/libs/Java-Profi-all.jar:projectdir/build/requiredLibs ch14_javafx.basics.FirstJavaFxExample

错误:

Prism pipeline init order: es2 sw 
Using java-based Pisces rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.sun.prism.es2.ES2Pipeline
Loading ES2 native library ... prism_es2
GraphicsPipeline.createPipeline failed for com.sun.prism.es2.ES2Pipeline
java.lang.UnsatisfiedLinkError: Can't load library: projectdir/build/libs/amd64/libprism_es2.so
*** Fallback to Prism SW pipeline
Prism pipeline name = com.sun.prism.sw.SWPipeline
GraphicsPipeline.createPipeline failed for com.sun.prism.sw.SWPipeline
java.lang.UnsatisfiedLinkError: Can't load library: projectdir/build/libs/amd64/libprism_sw.so
Graphics Device initialization failed for :  es2, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
Caused by: java.lang.RuntimeException: No toolkit found

找到 Gradle

的解决方案 我找到了两个解决方案,只有第一个使用胖 JAR:
  1. 使用 fat JAR
  2. 的伪启动器 class 的 quick-n-dirty 解决方案
  3. Jmods/modularization 的长期解决方案(不适合我使用 fat JAR)

我无法使长期解决方案与胖 JAR Java-Profi-all.jar 一起工作。无论如何,您可以在此处找到有关模块化解决方案的更多信息:

  • https://edencoding.com/runtime-components-error/
  • 上的“使您的应用模块化”
  • How to fix "Error: JavaFX runtime components are missing, and are required to run this application" : "简而言之,您必须通过添加 javafx 模块来编译/运行,或者作为在命令行上传递的选项,或者使用模块化项目。"
  • Gradle 不使用 Gradle-插件的解决方案 org.openjfx.javafxplugin :

使用 fat JAR 的 quick-n-dirty 解决方案

为了用Gradle执行classch14_javafx.basics.FirstJavaFxExample我写了classJfxEdencodingDirtyFixLauncher 同包:

package ch14_javafx.basics;

public class JfxEdencodingDirtyFixLauncher {
    public static void main(String[] args){
        FirstJavaFxExample.main(args);
    }
}

另外我对build.gradle做了如下修改:

A) 确保使用的 openjfx 版本适合 JRE 版本。

sourceCompatibility=1.11
targetCompatibility=1.11

B) 手动将 openjfx-JAR 和 C++ 库 (*.so) 添加到构建配置中(由于我的 linux 安装):

dependencies
{
...
    compile fileTree('/usr/local/manuell/javafx-sdk-11.0.2/lib/') { include '*.jar' }
    runtime fileTree('/usr/local/manuell/javafx-sdk-11.0.2/lib/') { include '*' } // also inlcude *.so files for JNI-access
...

gradle.build-脚本随后将这些 *.jar 和 *.so 文件复制到子文件夹 requiredLibs 和在构建 JAR jar 时将它们添加到 class 路径:

...
task copyRequiredLibs(type: Copy) {
   from configurations.runtime
   into "$buildDir/libs/requiredLibs"
}


jar {
  dependsOn copyRequiredLibs
  
  baseName = "Java-Profi-all"
  
  manifest {
    attributes(
               "Created-By"             : "Michael Inden",
                    "Specification-Title"    : "Java-Profi",
                    "Specification-Version"  : "3",
                    "Specification-Vendor"   : "Michael Inden",
                    "Implementation-Title"   : "Java-Profi",
                    "Implementation-Version" : "3",
                    "Implementation-Vendor"  : "Michael Inden",      
      "Class-Path": configurations.runtime.collect { "requiredLibs/" + it.getName() }.join(' '))
  }
  
  // JAR-Dateien mit aufnehmen, dann kann man diese bei Bedarf separat entpacken
  into('requiredLibs') {
    FileCollection collection = files("$buildDir/libs/requiredLibs")
    from { collection.collect { it } }
  }  
...

为了使用自定义 gradle 任务执行胖 JAR,我在预定义的 appTasks.txt 文件中添加了一个任务定义:

task JfxEdencodingDirtyFixLauncher              (dependsOn: jar, group: 'Java_Profi_Chapter_14') {doLast { executeClass("ch14_javafx.basics.JfxEdencodingDirtyFixLauncher")  }} 

然后可以通过以下命令使用胖 JAR 执行此任务:

gradle JfxEdencodingDirtyFixLauncher

另请参阅:

  • “在短期内修复运行时组件”,发表于 https://edencoding.com/runtime-components-error/ !
  • :“最终目标是让 JavaFX 模块作为模块路径上的命名模块,这看起来像是一个 quick/ugly 解决方法来测试您的应用程序。对于分发,我仍然建议使用上述解决方案。"
  • Error: JavaFX runtime components are missing, and are required to run this application in eclipse