博文目录
文章目录
- JavaFX 简单说明
- JavaFX 版本说明
- JavaFX 与 JDK 的关系
- JavaFX 与 JDK Modular (JDK 9 模块化系统)
- JavaFX 模块说明 (JavaFX 20)
- JavaFX Scene Builder
- 构建 JavaFX 应用程序的两种选择
- 环境搭建 `建议先阅读下方引用的官方文档, 与本章节做相互印证与理解`
- 版本选择
- JavaFX SDK (使用 Maven 等构建工具的无需下载 JavaFX SDK)
- IntelliJ Idea 安装配置
- IntelliJ Idea `Java Project` 开发方式
- 新建工程
- 添加 JavaFX SDK 依赖
- 关联 JavaFX SDK 源码
- 创建第一个 JavaFX 窗体
- HelloWorld.java
- 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
- 效果展示
- IntelliJ Idea `JavaFX Project` 开发方式 (Maven)
- 新建工程
- 自带初始模板代码如下
- pom.xml
- module-info.java
- HelloApplication.java
- hello-view.fxml
- HelloController.java
- 运行 HelloApplication
- Scene Builder 19.0.0 安装与配置
- JavaFX 开发需要掌握的知识点
- Java 模块化技术基础
- JavaFX 基础编程模型
- JavaFX MVC 架构
- JavafX 事件处理机制
- JavaFX 多窗体编程与数据传输
- JavaFX 数据绑定机制
- Java MVVM
- JavaFX 多线程
- JavaFX 集成第三方框架, 如 RxJava
- JavaFX Chart 图表
- 打包与分发
- 添加一个标准的
- 非模块化工程
JavaFX 简单说明
JavaFX 官网
JavaFX 是一个开源的下一代客户端应用程序平台,适用于基于 Java 构建的桌面、移动和嵌入式系统。它是许多个人和公司的协作成果,目标是为开发富客户端应用程序生成一个现代、高效且功能齐全的工具包。
JavaFX 主要致力于富客户端开发,以弥补 swing 的缺陷,主要提供图形库与 media 库,支持 audio,video,graphics,animation,3D 等,同时采用现代化的 css 方式支持界面设计。同时又采用 XUI 方式以 XML 方式设计 UI 界面,达到显示与逻辑的分离。与 android 这方面确实有点相似性。
Java 8 新特性探究(十三)JavaFX 8 新特性以及开发 2048 游戏
跟 java 在服务器端和 web 端成绩相比,桌面一直是 java 的软肋,于是 Sun 公司在 2008 年推出 JavaFX,弥补桌面软件的缺陷,请看下图 JavaFX 一路走过来的改进
从上图看出,一开始推出时候,开发者需使用一种名为 JavaFX Script 的静态的、声明式的编程语言来开发 JavaFX 应用程序。因为 JavaFX Script 将会被编译为 Java bytecode,程序员可以使用 Java 代码代替。 JavaFX 2.0 之后的版本摒弃了 JavaFX Script 语言,而作为一个 Java API 来使用。因此使用 JavaFX 平台实现的应用程序将直接通过标准 Java 代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView 可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。从 JDK 7u6 开始,JavaFX 就与 JDK 捆绑在一起了,JavaFX 团队称,下一个版本将是 8.0,目前所有的工作都已经围绕 8.0 库进行。这是因为 JavaFX 将捆绑在 Java 8 中,因此该团队决定跳过几个版本号,迎头赶上 Java 8。
目前我还不知道 Java 平台其他的更好的客户端库
JavaFX 版本说明
官网 版本说明
截止到 20230423, JavaFX 的版本如上图所示. 有几个点需要注意
- JavaFX 11 和 17 是长期支持版本, 会有专人做更新和修复工作, 除此之外的版本都是非长期支持版本
- JavaFX 11 虽然是长期支持版本, 但是其将在 202309 到期, 而且有更好的 17 可选, 所以 11 不推荐使用
- JavaFX 20 是当前的最新发布版本, 但不是长期支持版本. 最新发布版本会有最多最全的新特性, 有需要可以使用该版本
- JavaFX 21 是早期访问版本, 相当于测试版本, 一般不建议使用, 看中某些新特性尝鲜可以试试
- 灰色的 JavaFX 12 / 13 / 14 / 15 / 16 / 18 已经不再更新, 不建议使用. 19 虽然还在更新, 但是估计用不了多久也会停止, 同样不建议使用
综上所述, 比较推荐 JavaFX 17 / 20, 17 有长期支持, 20 有最新最全的特性
JavaFX 与 JDK 的关系
JavaFX 建立在 JDK 之上,是一个独立的组件。
从 JDK 11 开始, JavaFX 与 JDK 分开发布, JavaFX 不再集成于 JDK 中
JavaFX | JDK |
---|---|
20 | 17 or later |
19 | 11 or later |
18 | 11 or later |
17 | 11 or later |
16 | 11 or later |
15 | 11 or later |
14 | 11 or later |
13 | 11 or later |
12 | 11 or later |
11 | OpenJDK 10 / JDK 11 or later |
… | |
8 | 集成于 JDK 8 |
… |
JavaFX 与 JDK Modular (JDK 9 模块化系统)
在 Java 8 之后,JavaFX 从 JDK 中分离出来,然后在 Java 9 时,Java 引入了 Java 模块化系统。从那之后,JavaFX 要求使用 Java 模块化系统来运行 JavaFX。因此,当直接使用 Java 8 以上的环境运行非模块化的 JavaFX 项目时就会出现如下报错。
错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
解决方法见下文 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
部分
JavaFX 模块说明 (JavaFX 20)
官网 JavaFX 20 API 文档
- javafx.base: 定义 JavaFX UI 工具包的基本 API,包括绑定、属性、集合和事件的 API。
- javafx.controls: 定义可用于 JavaFX UI 工具包的 UI 控件、图表和外观。
- javafx.fxml: 为 JavaFX UI 工具包定义 FXML API。
- javafx.graphics: 为 JavaFX UI 工具包定义核心场景图 API(例如布局容器、应用程序生命周期、形状、转换、画布、输入、绘画、图像处理和效果),以及动画、CSS、并发、几何、打印的 API , 和开窗。
- javafx.media: 定义用于播放媒体和音频内容的 API,作为 JavaFX UI 工具包的一部分,包括MediaView和 MediaPlayer.
- javafx.swing: 为 JavaFX UI 工具包中包含的 JavaFX/Swing 互操作支持定义 API,包括SwingNode(用于将 Swing 嵌入 JavaFX 应用程序)和 JFXPanel(用于将 JavaFX 嵌入 Swing 应用程序)。
- javafx.web: 为 JavaFX UI 工具包中包含的 WebView 功能定义 API。
JavaFX Scene Builder
官网 Scene Builder 下载
Scene Builder 是针对 JavaFX FXML UI 的拖拽式页面设计编码工具, 免费且开源
当前版本是 Scene Builder 19.0.0, 运行需要 JDK 11 or later
如果使用 JDK 8 的 JavaFX, 可以下载 Scene Builder 8.5.0
构建 JavaFX 应用程序的两种选择
- JavaFX SDK, 原生 Java SE 工程开发 JavaFX 应用程序, 需要下载并引入 JavaFX SDK 提供的依赖 jar, 在 lib 目录下
- Maven / Gradle 等构建工具, 使用构建工具可以从中央仓库下载指定版本的 JavaFX 相关依赖, 和使用 JavaFX SDK 本质是一样的
建议选择使用 Maven 等构建工具
环境搭建 建议先阅读下方引用的官方文档, 与本章节做相互印证与理解
官网 JavaFX 和 IntelliJ IDEA
版本选择
本次学习使用最新版 JavaFX 20, 所以需要使用 JDK 17
JavaFX SDK (使用 Maven 等构建工具的无需下载 JavaFX SDK)
官网 JavaFX SDK 下载
- 先选择合适的 SDK 版本, 建议从 11 / 17 / 20 / Early Access 这 4 个版本中选择
- 然后下载并解压该 SDK, 如
C:\mrathena\develop\javafx-sdk-20.0.1
IntelliJ Idea 安装配置
略
IntelliJ Idea Java Project
开发方式
以这种方式创建的工程默认是非模块化工程, 如果需要改成模块化工程, 需自行添加并编写 module-info.java
module-info.java 与包结构的起始路径在同一个目录下
新建工程
初始工程结构如下
添加 JavaFX SDK 依赖
打开工程结构设置
确保当前使用的是 JDK 17
在 Libraries 里添加 JavaFX SDK 的 lib 目录, 其下所有 jar 文件都会被自动依赖到工程中
关联 JavaFX SDK 源码
随便打开一个 JavaFX 的 class 文件, 如 javafx.application.Application
, Idea 上方会提示 Choose sources ...
即可选择合适的源码关联, JavaFX SDK 的源码就是文件夹下的 src.zip
创建第一个 JavaFX 窗体
HelloWorld.java
package com.mrathena;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
@Override
public void start(Stage stage) throws Exception {
String javaVersion = System.getProperty("java.version");
String 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();
}
public static void main(String[] args) {
launch();
}
}
错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
当使用 Java 8 以上的环境运行非模块化的 JavaFX 项目时就会出现如下报错
错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
解决方法也有多种
-
使用 JDK 8, 不建议, 不能从根源解决问题
-
改造本工程为模块化工程,
推荐使用该方法
. 添加 module-info.java 模块申明文件, 内容如下module com.mrathena { // 定义模块名称, 通常和包名一致 requires javafx.controls; // 引入 javafx.controls 模块 exports com.mrathena; // 暴露本模块中的指定包(不包含子包) // Caused by: java.lang.IllegalAccessException: class com.sun.javafx.application.LauncherImpl (in module javafx.graphics) cannot access class com.mrathena.HelloWorld (in module com.mrathena) because module com.mrathena does not export com.mrathena to module javafx.graphics }
-
在运行配置里添加 vm 参数
--module-path 下载的JavaFx的SDK的lib文件夹的完整路径 --add-modules javafx.controls,javafx.fxml
, 如果路径里有空格, 则路径要加上双引号""
为了方便, 可以给 JavaFX 运行模板配置该 vm 参数, 后续运行其他主类也会自动加上该参数 -
使用引导类, 在另一个类的 main 方法中调用主类的 main 方法, 会自动生成一个匿名的模块系统, 桌面程序可以运行, 但有警告提示
4月 23, 2023 10:19:53 下午 com.sun.javafx.application.PlatformImpl startup 警告: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @491dbe27'
效果展示
IntelliJ Idea JavaFX Project
开发方式 (Maven)
如果使用 Maven 开发 JavaFX 应用程序,则不必下载 JavaFX SDK。只需在 pom.xml 中指定想要的模块和版本,构建系统就会下载所需的模块,包括所属平台的本机库。本机库就是不同系统下的具体实现, 如下图中带 win 的依赖
如
- D:\resource\develop\maven\repository\org\openjfx\javafx-controls\20.0.1\javafx-controls-20.0.1.jar
- D:\resource\develop\maven\repository\org\openjfx\javafx-controls\20.0.1\javafx-controls-20.0.1-win.jar
新建工程
通过 Idea JavaFX Project 创建的就是 Maven 工程, 或者也可以创建 JavaFX Archetype 的 Maven 工程(需要自行导入该骨架), 不如 Idea JavaFX Project 来的方便
不知道这些依赖是干什么的先不选, 初始工程结构如下
默认就是 模块化结构的工程, pom.xml 中 javafx 的依赖版本默认是 17.0.0.1, 改成 20.0.1 即可
自带初始模板代码如下
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mrathena</groupId>
<artifactId>javafx</artifactId>
<version>1.0-SNAPSHOT</version>
<name>java.javafx.starter</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>20.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>20.0.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.7</version>
<executions>
<execution>
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>com.mrathena.javafx/com.mrathena.javafx.HelloApplication</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
module-info.java
module com.mrathena.javafx {
requires javafx.controls;
requires javafx.fxml;
opens com.mrathena.javafx to javafx.fxml;
exports com.mrathena.javafx;
}
HelloApplication.java
package com.mrathena.javafx;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
hello-view.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.mrathena.javafx.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
HelloController.java
package com.mrathena.javafx;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
@FXML
private Label welcomeText;
@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
}
运行 HelloApplication
Scene Builder 19.0.0 安装与配置
官网 Scene Builder 下载
下载好 SceneBuilder-19.0.0.msi 并运行, 选择合适的安装位置, 安装即可
在 Idea 里右键某个 fxml 文件, 选择使用 SceneBuilder 打开, 即可设置与 SceneBuilder.exe 的关联, 设置过后, 后续即可直接用 SceneBuilder 打开 fxml 文件, 编辑好后 Ctrl+S 保存即可直接作用于 fxml 文件
JavaFX 开发需要掌握的知识点
Java 模块化技术基础
51-Java模块化技术基础
- module-info.java
- –module-path
- –add-modules
- jmods
- jlink
JavaFX 基础编程模型
54-把握JavaFX编程模型
- JavaFX 应用程序的主类需要继承自
javafx.application.Application
类, 然后重写其 start 方法, 此方法是所有 JavaFX 应用程序的入口点 - JavaFX 应用程序将 UI 容器定义为
舞台(Stage)
与场景(Scene)
, Stage 是顶级容器, 它对应于窗体, 其内容有 Scene 决定. Scene 是所有可视化内容的容器(Container)
. JavaFX 应用程序的可视化界面通常由控件(Control)
和形状(Shape)
构成, 放到 Scene 中 - JavaFX 中, Scene 中的内容会以由
图形节点(Node)
构成的分层场景图(Scene Graph)
来展现. SceneGraph 其实就是一颗多叉树, 各种控件都是树中的节点, 最底层的节点通常是诸如按钮之类的控件, 也可以是 Circle 之类的图形. 拥有子树的节点称为容器, 在 JavaFX 中称为布局(Layout)
- Stage 与 Scene 是 1:1 的关系, Scene 与场景图的根节点是 1:1 的关系
- JavaFX 应用程序的生命周期:
init
-start
-running
-stop
, init / start / stop 由抽象类 javafx.application.Application 定义, 可以自定义覆盖 - Stage 的生命周期: close / hide / show 等等, 可以给 Stage 挂接相关事件
JavaFX MVC 架构
55-JavaFX应用的MVC架构
- MainClass: 程序的入口点, 通常包容管理多窗体, 实现各控制器之间相互通讯的相关代码
- Model: 就是封装了数据的 JavaBean
- View: 使用 FXML 编写, 包容可视化的 UI 控件, 使用户使用程序的媒介, 关联着一个控制器
- Controller: 包容程序的应用逻辑, 负责响应用户操作, 负责在 View 和 Model 之间实现数据同步
JavafX 事件处理机制
56-把握JavaFX事件处理机制原理
- 桌面应用都是
事件驱动
的,事件(Event)
表示程序所感兴趣的某件事情发生了, 比如鼠标移动事件, 按键按下事件等 - JavaFX 中, 事件是 javafx.event.Event 类或其任何子类的实例, JavaFX 提供了多种事件, 比如 DragEvent(拖动事件), KeyEvent, MouseEvent 等, JavaFX 提供的内置 UI 控件和图形对象, 都可以触发特定事件
- JavaFX 中可以通过 Java 代码绑定事件, 也可以通过 FXML 绑定事件, 通过 FXML 声明的事件的方法要加 @FXML 注解
- 事件派发链: 事件在控件树中的传播过程. 事件派发链是一个双向链表, 有时间目标对象负责创建, 事件发生时, 事件对象会在链中传播. 事件响应方法分为 EventFilter 和 EventHandler 两类, 先执行 EventFilter 事件链
- EventFilter: 下沉: 从根节点向下来到事件发生节点
- EventHandler: 冒泡: 从事件发生节点向上去往根节点
- 举例: HBox 里放了个 Label: 两者都分别挂载了两个方向的 MOUSE_PRESSED 事件, 如果在标签上点击左键, 则会按照先 EventFilter 再 EventHandler 的顺序来调用响应方法, Filter 的先执行 hBox 的再执行 label 的, Handler 的先执行 label 的再执行 hBox 的
- hBox.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {})
- hBox.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {})
- label.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {})
- label.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {})
JavaFX 多窗体编程与数据传输
57-JavaFX多窗体编程
- 每个 Stage 对应一个窗体
- 模态窗体: 具有父子关系且子窗体出现时, 父窗体不能操作
- 对象互相传递消息: 就是对象互相持有引用, 调用对方的方法来传递数据, 在 JavaFX 中窗体间传递信息靠的就是各 Controller 相互引用, 调用回调函数
JavaFX 数据绑定机制
58-JavaFX数据绑定机制及应用
- JavaFX Bean Property: 提供了很多 SimpleIntegerProperty 之类的工具类, 可以绑定值改变事件, 代码操作值, 绑定的 UI 自动跟新
- JavaFX 数据绑定编程模式
- 绑定数据源: 具备改变通知能力的数据对象与数据集合, 包括
JavaFX Bean Property
/ObservableValue
/ObservableList<T>
- JavaFX 应用程序的 UI 界面: 包容 TableView / Label 等支持数据绑定的控件
- JavaFX 数据绑定机制: Binding 对象
- 举例: Circle 始终居于窗体中央, Circle 自带圆心横纵坐标的 Property 属性, Scene 自带宽度高度的 Property 属性
- circle.centerXProperty().bind(Bindings.divide(scene.widthProperty(), 2));
- circle.centerYProperty().bind(Bindings.divide(scene.heightProperty(), 2));
- 绑定数据源: 具备改变通知能力的数据对象与数据集合, 包括
- 优点: 业务逻辑与 UI 分离, 绑定好关系之后, 属性值变化, UI 会自动更新, 无需代码修改 UI
- 双向绑定:
- 举例: 两个 TextField 保持内容一致, 再任何一方修改, 另一方保持内容相同
- repeater.textProperty().bindBidirectional(speaker.textProperty());
- 举例: 两个 TextField 保持内容一致, 再任何一方修改, 另一方保持内容相同
Java MVVM
59-JavaFX实现MVVM架构
- View: 还是 FXML 定义的 UI
- ViewModel: 和 MVC 中的 Model 一样, 但是使用
JavaFX Bean Property
/ObservableValue
/ObservableList<T>
具备值变化通知能力的工具来做成员属性, 其与 UI 上的某些控件的值相对应 - Controller: 实现
javafx.fxml.Initializable
接口, 在其提供的 initialize 方法中做如下事情- 控件的事件挂载
- ViewModel 和 UI 控件做双向数据绑定, 这样 Controller 直接操作 ViewModel 的属性即可同步到 UI, 在 UI 相关控件上修改值也能同步到 ViewModel 的相关字段中
- 注意: UI 变化完全由数据绑定后自行更新, Controller 不做任何 UI 的控制
- 举例: 登录功能, UI 有 username 和 password 两个 TextField, login 和 cancel 两个 Button
- LoginApplication: 程序主类入口
- LoginViewModel: 持有 usernameProperty 和 passwordProperty 两个 StringProperty, 还有相关的 getter / setter / protertyGetter
- LoginController: 实现 login 和 cancel 两个方法, 在 initialize 方法中做 login 按钮和 login 方法的绑定, cancel 按钮和 cancel 方法的绑定, ViewModel 中 usernameProperty 和 username 文本框的双向绑定, ViewModel 中 passwordProperty 和 password 文本框的双向绑定
- login: 通过获取并验证 ViewModel 中 usernameProperty 和 passwordProperty 的值做合适的逻辑处理
- cancel: 清空 ViewModel 中 usernameProperty 和 passwordProperty 的值
- 也可以把 login 中的业务逻辑放到其他方法或类中, 这样 单元测试 时可以只测业务不看 UI
JavaFX 多线程
60-JavaFX多线程及典型示例展示
- UI 操作有专门的
JavaFX Application Thread
线程负责, 自行创建的线程不允许操作 UI - 主线程中不要直接调用耗时很久的方法, 会导致窗体冻结. 要用一个线程去这些任务, 如果任务完成后需要更新 UI, 则可以使用
Platform.runLater(() - > {})
的方式, 这里 Lambda 表达式执行的操作会被推送到 JavaFX Application Thread 线程中执行, 所以可以访问 UI 控件 - JavaFX 的 Worker 和 Task: 提供了后台线程运行并更新 UI 的相关功能封装, 支持中途取消
JavaFX 集成第三方框架, 如 RxJava
- RxJava: 一款响应式的框架
- 需要注意一点, 需要更新 UI 的地方用 Platform.runLater
JavaFX Chart 图表
- JavaFX 内置了 图表 相关控件, 支持数据绑定, 可做一些数据可视化相关功能
打包与分发
- Fat Jar: 运行时不再需要 -classpath 参数, 将依赖 Jar 中的相关类抽取到目标 Jar 包中