• 在 Intellij IDEA 里使用 OpenJFX (JavaFX)


    JDK 11 把 JavaFX 剥离了出来,形成了单独且开源的 OpenJFX 模块。

    本文的目的是通过简单的例子解释这一变化对使用 JavaFX 所造成的影响,并找到一种在 IDEA 2018.2 上使用它的办法。

    首先,OpenJFX 官网的入门文档指示我们手动下载 SDK,但在 maven 的帮助下这不是必须的。虽然同样得下载,但这被 maven 自动化了。

    我们的 pom.xml 如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>sample</groupId>
        <artifactId>javafx</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <mainClass>sample.JFXMain</mainClass>
            <javafx.version>11</javafx.version>
        </properties>
    
        <dependencies>
    
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>${javafx.version}</version>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>${javafx.version}</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                    <configuration>
                        <source>11</source>
                        <target>11</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    这里引入了 OpenJFX 的依赖包,并设置了项目的 JDK 版本为 JDK 11。

    根据 IDEA 的提示 Import Changes,或者手动:右键 pom.xml - Maven - Reimport。

    注意:这里没有使用 maven.compiler.source 和 maven.compiler.target 这两个 property。这两个 property 是作为参数定义在 maven-compiler-plugin 里的,分别对应于源代码的 Java 版本和目标代码的 Java 版本。因为 IDEA 目前对这两项的支持似乎不够好,不能完美地同步到项目设置里。

    注意:需要手动检查 Preferences - Build, Execution, Deployment - Compiler - Java Compiler 中 Project bytecode version 及 Per-module bytecode version 的值是否同为 11。理由同上。

    我们的 Java 代码如下:

    package sample;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class JFXMain extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception{
            Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    package sample;
    
    public class Controller {
    }
    

    OpenJFX 布局描述文件 /src/main/resources/sample.fxml 如下:

    <?import javafx.scene.layout.GridPane?>
    <GridPane fx:controller="sample.Controller"
              xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    </GridPane>
    

    Java 模块描述文件 /src/main/java/module-info.java 如下:

    module sample {
        requires javafx.controls;
        requires javafx.fxml;
    
        // 暴露包 sample 给 javafx 的模块们,使其可以在运行时使用反射访问
        opens sample to javafx.graphics, javafx.fxml;
    }
    

    以上便是在 JDK 11 中使用 OpenJFX 所需的全部铺垫了。

    常见错误

    启动报错:缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序

    模块化 Java 程序与非模块化 Java 程序的启动方式有所不同。

    # 非模块化
    java [options] mainclass [args...]
    
    # 模块化
    java [options] [--module-path modulepath] --module module[/mainclass] [args...]
    

    提供了 module-info.java 的话,IDEA 发现这是模块化的 Java 程序。以上例为例,启动命令是:

    java ${OPTIONS} -m ${METHOD_PATH} -m sample/sample.JFXMain
    

    否则,IDEA 会认为这是非模块化 Java 程序,启动命令是:

    java ${OPTIONS} -classpath ${CLASS_PATH} sample.JFXMain
    

    但这报错具体是什么代码引起的呢?我们在 JDK 11 的 sun.launcher.LauncherHelper 发现:如果 JFXMain 继承自 javafx.application.Application,同时程序从 JFXMain.main() 启动,LauncherHelper 会检查是否存在模块 javafx.graphics 的声明:

    package sun.launcher;
    
    public final class LauncherHelper {
    
        static final class FXHelper {
    
            private static void setFXLaunchParameters(String what, int mode) {
                ...
                Optional<Module> om = ModuleLayer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME);
                if (!om.isPresent()) {
                    abort(null, "java.launcher.cls.error5");
                }
                ...
            }
        }
    }
    

    显然,如果不以模块化 Java 程序的方式启动,没有模块信息。错误码 java.launcher.cls.error5 即为 “错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序。”

    不过我们还有其他办法来绕开 LauncherHelper 的检查,能够以非模块化 Java 程序的方式运行程序。思路是:使程序的入口 main() 不继承自 javafx.application.Application

    因此,我们可以使用 maven 来运行程序,因为 maven 的 main() 显然满足该要求。这用到了 exec-maven-plugin,这个插件是默认包含的,我们可以直接使用它的 property exec.mainClass

    修改 pom.xml

    <properties>
        ...
        <exec.mainClass>sample.JFXMain</exec.mainClass>
        ...
    </properties>
    

    运行命令如下:

    mvn clean compile exec:java
    

    除此之外,我们也可以单独创建一个启动类:

    package sample;
    
    import javafx.application.Application;
    
    public class AppMain {
    
        public static void main(String[] args) {
            Application.launch(JFXMain.class, args);
        }
    }
    

    从这个类启动 Java 程序,效果相同。

    编译报错:Error: (4, 1) java: -source 8 中不支持 模块

    根据上文所述的方法,检查并修改 Project bytecode version。


    原文链接 https://blog.xupu.name/p/using-openjfx-in-intellij-idea/

     
  • 相关阅读:
    第一次个人编程作业
    第一次软工作业
    [Manacher]最长回文子串
    面向对象程序设计 总结作业
    面向对象程序设计 小黄衫晒单
    面向对象程序设计 作业三
    面向对象程序设计 作业二
    面向对象程序设计 作业一
    SSD/Memory技术学习拼图
    第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/javalinux/p/14802948.html
Copyright © 2020-2023  润新知