【问题标题】:Bundle in JavaFX when you run the executable from a Gradle project?从 Gradle 项目运行可执行文件时在 JavaFX 中捆绑?
【发布时间】:2020-03-08 20:25:43
【问题描述】:

在过去的几天里,我一直在努力寻找圣杯:Gradle + Java 11 + JavaFX + 用 Groovy 而非 Java 编写我所有的应用程序和测试代码。

其中一个问题是 Groovy 2(甚至是 Groovy 3)还不能处理 Java 9+ 模块,这将 one clever solution 排除在外。

但是我已经成功地获得了一个 Gradle 项目,它不仅成功地完成了几乎所有的事情,包括“运行”任务(来自“应用程序”插件),并且使用 TestFX 运行测试!这确实是在使用 Java 11、Groovy 2.5.9、JavaFX 13 等。

它甚至会执行任务“installdist”(当包含在 build.gradle 中时)。这会生成一个可执行文件,其中包含一个“lib”目录,其中包含您需要独立运行的所有 jar(如任务“assemble”,只是未压缩)。

问题是,当我执行该可执行文件时,我得到了现在经典的“错误:JavaFX 运行时组件丢失,并且需要运行此应用程序”。仍然困惑为什么会发生这种情况,因为目录 [project dir]/build/install/GradleExp/lib 确实包含不少于 7 个 JavaFX .jar。

我想我已经用尽了尝试常规配置 Gradle 的能力:鉴于我正在使用 Groovy 进行应用程序和测试代码,我认为不可能将 Gradle 项目配置为让“installdist”生成一个可立即运行的启用 JavaFX 的可执行文件。但是...生成这个之后我能做些什么吗,比如我可以运行的一些命令会以某种方式引入 JavaFX 文件并将它们链接起来?即使这涉及不雅地链接到某些 JavaFX jar 文件或位置?

或者我可以使用 .../build/scripts 下的“build”任务生成的可执行 sh 脚本文件?在定义 CLASSPATH 时,这会在上述 7 个 JavaFX .jar 文件中出现:

...
CLASSPATH=$APP_HOME/lib/GradleExp-1.0.jar:
$APP_HOME/lib/commons-math3-3.6.1.jar:
$APP_HOME/lib/guava-27.0.1-jre.jar:
$APP_HOME/lib/javafx-fxml-13-linux.jar:
$APP_HOME/lib/javafx-controls-13-linux.jar:
$APP_HOME/lib/javafx-controls-13.jar:
$APP_HOME/lib/javafx-graphics-13-linux.jar:
$APP_HOME/lib/javafx-graphics-13.jar:
$APP_HOME/lib/javafx-base-13-linux.jar:
$APP_HOME/lib/javafx-base-13.jar:...

...当我尝试运行该脚本时,我得到:

mike@M17A /.../GradleExp/build/scripts $  ./GradleExp
Error: Could not find or load main class SceneSwitcher
Caused by: java.lang.ClassNotFoundException: SceneSwitcher

编辑
这是一件有趣的事情:事实上,该脚本文件中的 APP_HOME 原来是 [项目目录]/build。但在那之下没有目录“lib”。有一个目录“libs”,其中只包含一个文件:GradleExp-1.0.jar,27 kB,不是想象中的“胖”jar。

我刚刚将“lib”目录从“installdist”任务复制到 /build,然后运行该脚本文件:再次,尽管现在所有这些 JavaFX jar 都可用,但我再次得到 “错误:JavaFX 运行时缺少组件,并且是运行此应用程序所必需的”。嗯……我还有很多东西要学。

【问题讨论】:

  • 如果 (1) 您将 JavaFX 模块放在类路径中并且 (2) 您的主类是 @ 的子类987654325@,那么这可能是您问题的根源。当您的主类是 Application 的子类时,javafx.graphics 模块 必须 位于模块路径上。这是当前如何实现 JavaFX 的特殊启动处理的结果。因此,如果您想要类路径上的 JavaFX 模块,请创建一个不扩展 Application 的单独主类,并从主方法调用 Application.launch(YourApp.class, args)
  • 我试图为我整理一个示例并且遇到了不同的问题,@Slaw 的评论解决了这些问题。我的示例项目是here
  • 非常感谢两位。为了未来的用户,也许你们中的某个人想回答这个问题?

标签: gradle javafx groovy java-11


【解决方案1】:

Slaw 和 cfrick 在他们的 cmets 中找到了我的问题的答案。我认为这可能对某些人有用。

如果您想要类路径中的 JavaFX 模块,则创建一个不扩展 Application 的单独主类,并从 main 方法调用 Application.launch(YourApp.class, args)

cfrick 的示例精简工作 Gradle 项目是 here。我添加了以下行:

installDist{}

...这使得一个新任务可用:./gradlew installdist 然后将在 build/install/ 下生成一个可执行文件。

万一cfrick的github页面消失了,build.gradle是这样的:

plugins {
    id 'groovy'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

repositories {
    jcenter()
}

javafx {
    version = "11.0.2"
    modules = [ 'javafx.controls' ]
}

dependencies {
    implementation 'org.codehaus.groovy:groovy:3.+'
}

application {
    mainClassName = 'ofx.App'
}

installDist{} // my addition

而 src/main/groovy/ofx/App.groovy 是这样的:

package ofx

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.stage.Stage

class App {
    static void main(String[] args) {
        Application.launch(HelloFx, args)
    }
}

class HelloFx extends Application {

    @Override
    void start(Stage stage) {
        def javaVersion = System.getProperty("java.version")
        def javafxVersion = System.getProperty("javafx.version")
        Label l = new Label("Hello, JavaFX $javafxVersion, running on Java $javaVersion.")
        Scene scene = new Scene(new StackPane(l), 640, 480)
        stage.setScene(scene)
        stage.show()
    }

}

【讨论】:

  • 没关系,继续。
猜你喜欢
  • 2021-05-17
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 2013-01-22
  • 2020-05-21
  • 1970-01-01
  • 2021-06-28
  • 1970-01-01
相关资源
最近更新 更多