【问题标题】:How to deploy JavaFX 15 Code to JAR with Java 15如何使用 Java 15 将 JavaFX 15 代码部署到 JAR
【发布时间】:2021-04-27 17:59:13
【问题描述】:

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

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

我在我现有的项目和一个全新的项目上尝试了以上所有方法,当你创建一个新的 JavaFX 项目时,除了 Intellij 的预先编写的东西之外,里面什么都没有。

我的项目不存在 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

【问题讨论】:

  • 既然已经在使用 Java 15,为什么还要使用过时的 JavaFX 11?
  • 我想是因为 javafx 11 是为了长期支持,但你建议升级到 javafx 15 吗?这会很容易完成并帮助我实现获得可以运行的罐子的目标吗?
  • 第一步是使用jlink创建自定义jre。然后使用平台相关(本机)启动器来启动 jvm,并为您的应用程序提供适当的参数。最后,制作一个安装包(本机)来复制客户端机器上的所有内容。
  • @mrmcwolf 我尝试创建一个新项目来逐步测试,如openjfx.io/openjfx-docs/#IDE-Intellij 中所述(在 IDE 的模块化下),但如果我从第 7 步运行最后一个命令,我会收到错误 ->我将错误消息添加到我的问题中
  • @Maxi 使用最新的 javafx。

标签: java javafx deployment jar


【解决方案1】:

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

简短说明

我解决了“初始化 QuantumRenderer 时出错:找不到合适的管道” 在 Gradle 的帮助下手动将库文件包含到 fat JAR 中并将它们添加到用于执行的类路径中。 包括我:
  • 我系统的 openJFX 安装所需的 openJFX-JAR
  • 随附的 C++ 库,例如渲染器 libprism_sw.so(Linux 上为 *.so,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 位置。这样就足够了。”

完整解释

“初始化 QuantumRenderer 时出错”问题

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

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

使用的命令:

/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. 使用胖 JAR 的伪启动器类的快速-n-dirty 解决方案
  2. 使用 Jmods/模块化的长期解决方案(不适用于我的胖 JAR)

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

使用胖 JAR 的快速 n-dirty 解决方案

为了使用 Gradle 执行类 ch14_javafx.basics.FirstJavaFxExample,我在同一个包中编写了类 JfxEdencodingDirtyFixLauncher

package ch14_javafx.basics;

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

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

A) 确保使用的 openjfx-version 适合 JRE-version。

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 时将它们添加到类路径中:

...
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 任务执行 fat JAR,我在预定义的 appTasks.txt 文件中添加了一个任务定义:

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

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

gradle JfxEdencodingDirtyFixLauncher

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2016-04-29
    • 2021-04-30
    • 1970-01-01
    • 2014-09-03
    • 2018-06-28
    • 1970-01-01
    相关资源
    最近更新 更多