JavaFX 和 Gradle:加载默认视图的正确方法是什么?

JavaFX and Gradle: What is the correct way to load a default view?

我不断收到“此版本中使用了已弃用的 Gradle 功能,使其与 Gradle 8.0 不兼容。”

我查看并尝试了十几个修复程序和教程,但都出现了同样的错误。我已将视图移至每个文件夹并将其重命名,以防不允许使用下划线。我已经尝试了我能想到的“/path/file.fxml”的所有排列

我感觉我的代码被贬低了,但我所能做的就是让 intellij 突出显示 .load()

这是我的代码:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class ScoreSheet extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
    FXMLLoader fxmlLoader = new 
FXMLLoader(ScoreSheet.class.getResource("views/main_menu.fxml"));
    primaryStage.setTitle("Score Sheet");
    Group root = new Group();
    Scene scene = new Scene(fxmlLoader.load(), 405, 720);
    primaryStage.setScene(scene);
    primaryStage.show();

    }
}

这是我的堆栈跟踪:

Starting Gradle Daemon...
Connected to the target VM, address: '127.0.0.1:51285', transport: 'socket'
Gradle Daemon started in 616 ms

> Configure project :
Found module name 'ScoreSheetTest.main'
Disconnected from the target VM, address: '127.0.0.1:51285', transport: 'socket'

> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :jar UP-TO-DATE
Connected to the target VM, address: 'localhost:51290', transport: 'socket'
Disconnected from the target VM, address: 'localhost:51290', transport: 'socket'
Connected to the target VM, address: '127.0.0.1:51285', transport: 'socket'

> Task :ScoreSheet.main() FAILED

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

See https://docs.gradle.org/7.2/userguide/command_line_interface.html#sec:command_line_warnings
3 actionable tasks: 1 executed, 2 up-to-date
Exception in Application start method
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:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalStateException: Location is not set.
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2541)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
    at ScoreSheetTest.main/com.company.scoresheet.ScoreSheet.start(ScoreSheet.java:16)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1(LauncherImpl.java:847)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait(PlatformImpl.java:484)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':ScoreSheet.main()'.
> Process 'command '/Users/username/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1


BUILD FAILED in 4s
Disconnected from the target VM, address: '127.0.0.1:51285', transport: 'socket'
2:05:57 PM: Execution finished ':ScoreSheet.main()'.

编辑:文件结构图像

编辑 2:这是我的 build.gradle:

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

group 'com.iharptech'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation 'org.openjfx:javafx-controls:18'
}

test {
    useJUnitPlatform()
}

sourceSets {
    main {
        resources {
            srcDirs = ["src/main/java"]
            includes = ["**/*.fxml"]
        }
    }
}

Gradle 弃用警告

这些警告几乎肯定与您的 IllegalStateException.

无关

如果您想知道使用了哪些已弃用的功能,那么您可以按照警告消息的说明进行操作并使用 --warning-mode all。如果您自己的构建脚本使用了这些功能,那么您可以查找替换项并自行解决问题。但是,如果插件使用了这些功能,那么您唯一的选择是:(1) 更新以使用最新版本的插件; (2) 如果已经在使用最新版本,请向插件作者提交错误报告(如果尚不存在); (3) 也许,如果可能的话,使用不同的插件。


将 Gradle 与 IDE

结合使用

当您使用诸如 Gradle(或例如 Maven)之类的构建工具时,您应该让构建工具处理所有依赖项和其他配置(尽可能多)。换句话说,您应该在构建脚本中声明 JavaFX 依赖项,而不是在 IntelliJ 中。

您还应该将 IDE 构建和 运行 任务委托给 Gradle。这样 Gradle 负责所有与构建相关的事情,而 IDE 只负责使编写代码更容易。

IntelliJ 与 Gradle 配合得非常好。您添加到 Gradle 的任何依赖项都将被 IntelliJ 识别。 Gradle 提供的任何任务也将被 IntelliJ 识别。

在 Gradle

中声明 JavaFX 依赖项

您正在使用 OpenJFX javafx-gradle-plugin。该项目的自述文件包含有关如何声明项目需要哪些 JavaFX 模块的文档。 请注意,此插件的最新版本是 0.0.12。您应该更新构建脚本以使用该版本。

本地 JavaFX SDK

如果您使用的是下载的 JavaFX SDK,正如您的评论所暗示的那样,那么您可以使用:

javafx {
    sdk = '/path/to/sdk' // replace with your own path
    modules = ['javafx.controls', 'javafx.fxml'] // modify list as needed
}

对于 sdk 路径,您可能需要设置一个变量,然后由调用 Gradle 的人传递。这样其他计算机上的人仍然可以在不修改构建脚本的情况下构建您的项目。虽然如果这是单台计算机上的个人项目,那么静态的绝对路径现在应该没问题。

不知道这个功能是什么时候添加到插件中的,所以您可能需要更新到最新版本。

Maven 中央 JavaFX JAR

您可以 Gradle 从 Maven Central 下载所需的 JavaFX JAR 文件。

javafx {
    modules = ['javafx.controls', 'javafx.fxml'] // modify list as needed
    version = '18' // change version as needed
}

repositories {
    mavenCentral()
}

正在执行 Gradle 个任务

您应该进行 运行 配置以执行 Gradle 任务,而不是让 IDE 使用自己的构建和执行系统。

要通过 IntelliJ 执行任何 Gradle 任务,您可以打开 Gradle 选项卡(如果我没记错的话,通常在 IntelliJ 的右侧),select一个任务,然后执行它。

或者您可以手动创建“运行 配置”。当 select 配置类型时,请务必选择“Gradle”。告诉它任务是针对哪个项目的,要执行哪个任务。

应用程序插件

通常,对于 JVM 项目,当您希望能够执行您的项目时,您应该应用 application 插件。

plugins {
    // other plugins...
    'application'
}

你已经这样做了。但是您还需要配置主 class 和主模块(如果存在)。

application {
    mainModule = '<module-name>'
    mainClass = '<fully-qualified-class-name>'
}

application 插件添加了 run 任务。要执行您的项目,请让 IntelliJ 执行 run 任务。


资源

有关资源的一般信息、如何加载它们、使用什么路径以及一些故障排除技术,我推荐这个问答:

但特别是关于您的设置,您应该从 Gradle 构建脚本中删除此部分:

sourceSets {
    main {
        resources {
            srcDirs = ["src/main/java"]
            includes = ["**/*.fxml"]
        }
    }
}

不需要。保留它意味着 src/main/resources 不再被视为资源根,您可能不想要它。

有了这个改变,并通过 run 任务执行项目,使用 "/views/main_menu.fxml" 作为资源路径应该适合你。