14.5 JavaFX
图形界面家族的第二代成员:Swing 是老一辈,JavaFX 是新一代(更漂亮、支持 CSS/动画/多媒体/FXML 界面文件)。套路和 Swing 高度同构:Stage 舞台 → Scene 场景 → Node 节点三层,对照 Swing 的套娃三层一翻就懂。本节定位是"会认、会跑一个最小程序"——概念新朋友,思想全老熟人。
一、JavaFX 是谁:Swing 的新一代兄弟
| Swing(14.1~14.4) | JavaFX(本节) | |
|---|---|---|
| 出生 | 1998,AWT 的升级 | 2008,Swing 的接班人 |
| 外观 | 传统桌面风 | 现代风,支持 CSS 美化 |
| 加分项 | 老项目遍地 | 动画、多媒体、FXML 界面文件、属性绑定 |
| 现状 | JDK 自带,随到随用 | JDK 8 内置;JDK 11 起被移出 JDK,要单独装 OpenJFX |
JDK 17 不自带 JavaFX。直接跑会报:"JavaFX runtime components are missing"(缺运行组件)。两条路:
1. IDEA 装库:File → Project Structure → Libraries → + → 下载/导入 OpenJFX(gluon 官网下 JavaFX SDK 解压,指到 lib 文件夹);
2. 加运行参数:Run Configuration → VM options 填 --module-path <SDK的lib路径> --add-modules javafx.controls。
配好一次终身受用;如果教材配套项目已经带好了,直接跑 Demo30 验收。
二、三层结构:舞台装场景,场景装节点
JavaFX 把界面拆成三层,跟 Swing 套娃一一对号:
| JavaFX | 职责 | Swing 对应(14.1) |
|---|---|---|
| Stage | 舞台=操作系统给的窗口 | JFrame |
| Scene | 场景=窗口里的一块幕布,一次放一块 | 内容面板 |
| Node | 节点=幕布上的演员(按钮/文本/布局) | JButton 等组件 |
规矩:Stage 装 Scene,Scene 装根节点,根节点再装其他节点——组件不能直接 add 给 Stage/Scene,必须先装进一个布局根节点。
三、Application 套路:四步最小骨架
写 JavaFX 程序 = 继承 Application 类、重写 start、launch 启动:
- 写个类
extends Application(4.1 继承老规矩); - 重写
start(Stage stage)——搭界面的代码全在这(用@Override标注,9.4); main里调launch(args)——它内部会自动造出你的对象、依次调init()→start();- 关窗后框架自动调
stop(),程序谢幕。
关键认知:init() / start() / stop() 都不是你调的,是框架代调的(模板方法,3.5 this 那章"父类定流程子类填内容"的思路)。你只管重写,别在 main 里自己 new Demo30().start(...) 抢戏——那样 launch 的配套环境根本没建起来,直接报错。
四、控件与布局对照表:换名字不换思想
Label lbl = new Label("还没点"); // ↔ JLabel
Button btn = new Button("点我"); // ↔ JButton
TextField txt = new TextField(); // ↔ JTextField(getText/setText 通用)
PasswordField pf = new PasswordField(); // ↔ JPasswordField
VBox root = new VBox(10, lbl, btn); // 垂直排列,间距 10 ↔ FlowLayout 纵向版
HBox row = new HBox(10, lbl, btn); // 水平排列
BorderPane bp = new BorderPane(); // ↔ BorderLayout,同样东南西北中
bp.setTop(node); bp.setCenter(node); // 摆位用 setTop/setBottom/setLeft/setRight/setCenter
事件也一样,只换了名字:btn.setOnAction(e -> ...) ↔ Swing 的 addActionListener——Lambda 照样上岗,e 照样是事件对象。思想零成本迁移。
五、动手:Demo30 JavaFX 第一扇窗
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Demo30 extends Application {
@Override
public void start(Stage stage) {
Label lbl = new Label("还没点");
Button btn = new Button("点我");
btn.setOnAction(e -> lbl.setText("你点过了!")); // 门铃:14.4 同款 Lambda
VBox root = new VBox(10, lbl, btn); // 根节点:垂直摆两样
Scene scene = new Scene(root, 300, 200); // 场景装根节点,300×200
stage.setTitle("JavaFX 第一扇窗");
stage.setScene(scene); // 舞台装场景
stage.show(); // ↔ setVisible(true)
}
public static void main(String[] args) {
launch(args);
}
}
跑起来:一个现代风格的窗口,点按钮标签变字——Swing 十四节学的每一招,在这里都有对应的影子。
报 JavaFX runtime components are missing——亲眼见一次这个错,按第一节的两条路配好,再跑就通了。配置错误是本节 90% 的翻车点。
btn.setOnAction(new EventHandler<ActionEvent>() {...})——长得跟 14.4 写法二一个模子。EventHandler 也是单方法函数式接口,所以最终都能瘦身成 Lambda。
把 VBox 换成 HBox:两个控件横着排;换 BorderPane 并 bp.setTop(lbl); bp.setCenter(btn);——标签顶上、按钮居中。布局师傅还是那批思路,只是按"流"改名为"Pane"。
六、五个常见误区
必报 missing components。JDK 11 起 JavaFX 不再内置——先配 OpenJFX(库 + VM 参数),再谈运行。
start 的舞台、场景环境都是 launch 建的。绕过 launch 直接调 start,内部资源全没就位,各种莫名报错。口诀:launch 负责"叫人",start 只管"演"。
Stage 只收 Scene,Scene 只收一个根节点。控件要先装进 VBox/HBox 等布局根节点,再 new Scene(root, ...)。
报 Not on FX application thread——JavaFX 界面只认自己的 UI 线程(对应 Swing 的 EDT)。第十二章的老道理在 GUI 里一样铁:界面只由 UI 线程摸,后台线程算完结果要交回主线程刷新(进阶再展开)。
两者是并存关系:Swing 老项目遍地(IDEA 本体就是 Swing 写的),JavaFX 主打新开发。教材讲 JavaFX 是让你"多认识一门",思想是同一套。
七、自测题
Stage 舞台=窗口(JFrame)、Scene 场景=幕布(内容容器)、Node 节点=演员(组件)。规矩:舞台装场景,场景装根节点。
JDK 11 起不内置 JavaFX:装 OpenJFX SDK(IDEA 加库)+ 运行参数 --module-path <lib路径> --add-modules javafx.controls。
不是。launch(args) 内部自动建环境后,由框架依次调 init() → start();关窗时调 stop()。你只管重写。
btn.setOnAction(e -> ...),对应 Swing 的 btn.addActionListener(e -> ...)——EventHandler 也是函数式接口,Lambda 照用。
参考骨架:
TextField name = new TextField();
PasswordField pwd = new PasswordField();
Label msg = new Label();
Button btn = new Button("登录");
btn.setOnAction(e -> {
if ("admin".equals(name.getText()) && "123456".equals(pwd.getText())) {
msg.setText("登录成功");
} else {
msg.setText("用户名或密码错误");
}
});
VBox root = new VBox(10, name, pwd, btn, msg);
自检:控件都装进根节点了吗?equals 而不是 ==(6.2)?消息用标签显示(也可以试 Alert 弹窗)?——到此 GUI 两大门派都摸过了。
八、下一步学什么
- ☑ 14.6 本章小结 ✅ —— 点此复习:五节串线、速查 15 条、模板 4 段、五大名坑、毕业大题完整登录窗(第十四章完结 🎉)
- ☐ 第十五章(按教材顺序) —— 报个标题接着走。等你报标题。
相关笔记
- 第十四章 图形用户界面/14.4 事件处理机制:setOnAction 与 addActionListener 是同一个思想的两种方言
- 第十四章 图形用户界面/14.1 Swing概述:套娃三层对照 Stage/Scene/Node,一翻就懂
- 第四章 面向对象(下)/4.1 继承:extends Application 是继承的又一次上岗
- 第十二章 多线程/12.1 进程与线程:UI 线程铁律的线程论出处