14.6 本章小结
GUI 全章收官:主线就是一句话——先画脸,再装灵魂。开窗(14.1)→ 摆居民(14.2)→ 排整齐(14.3)→ 装门铃(14.4)→ 拜新门派 JavaFX(14.5)。这条线的隐藏彩蛋:Demo27→28→29 是同一个表单的三次进化,从灰着哑着到点着有反应。
一、五节串线:一张表看完 GUI 这条线
| 节 | 主题 | 核心收获 | 关键 Demo |
|---|---|---|---|
| 14.1 | Swing概述 | AWT→Swing 家谱、套娃三层(JFrame→JPanel→组件)、开窗五步、点✕三档、JOptionPane 三件套 | Demo25/26 |
| 14.2 | 常见组件 | 三大家族(文本/按钮/选择)、通用三板斧、getPassword 返回 char[]、ButtonGroup 收编 | Demo27 |
| 14.3 | 布局管理器 | 三位师傅(Flow/Border/Grid)、setLayout 是容器属性、BorderLayout 两铁律、面板=快递箱 | Demo28 |
| 14.4 | 事件处理 | 事件三要素、addActionListener=装门铃、三种写法→Lambda、监听器追加不覆盖 | Demo29 |
| 14.5 | JavaFX | Stage/Scene/Node 三层、Application 套路(launch 代调)、setOnAction 表亲 | Demo30 |
二、概念速查(15 条)
| 概念 | 一句话 |
|---|---|
JFrame |
顶层窗口,开窗五步:new→setSize/位置→点✕档→add→setVisible(true) 最后 |
EXIT_ON_CLOSE |
点✕就退进程;默认档(HIDE)会让程序"假死"不退出 |
JOptionPane |
弹窗三件套:showMessageDialog / showInputDialog / showConfirmDialog |
| 三大家族 | 文本(Label/TextField/PasswordField/TextArea)、按钮(Button/CheckBox/RadioButton)、选择(ComboBox/List) |
| 三板斧 | setText 摆内容、getText 拿内容、setEnabled 管死活——几乎全组件通用 |
getPassword() |
密码框专用,返回 char[](用完可清零更安全),要 String 就 new String(pw) |
ButtonGroup |
单选互斥管理员:只管互斥不管摆放,收编后才能真正"单选" |
FlowLayout |
JPanel 默认,打字换行式排队 |
BorderLayout |
JFrame 默认,东西南北中五区;add 不给位置进中区,一区一组件后到顶先到 |
GridLayout |
行×列均分格子,行在前列在后 |
setLayout |
容器的属性(JFrame/JPanel 上调),不是组件的 |
| 事件三要素 | 事件源(谁出事)+ 事件对象(ActionEvent 信封)+ 监听器(事后干活) |
addActionListener |
装门铃;不装,按一万次也不响;装俩,俩都响 |
| Lambda 限制 | 只伺候函数式接口(单抽象方法);抓走的局部变量必须 effectively final |
| Stage/Scene/Node | JavaFX 三层:舞台装场景,场景装根节点;Application 的 init/start/stop 全由 launch 代调 |
三、代码模板四段(背下来直接用)
模板 1:开窗 + 组件 + 布局(界面骨架)
JFrame frame = new JFrame("标题");
frame.setSize(360, 220);
frame.setLocationRelativeTo(null); // 居中
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel north = new JPanel(); // 板子自带 FlowLayout
north.add(new JLabel("用户名"));
north.add(new JTextField(15));
JPanel south = new JPanel(new GridLayout(2, 2)); // 换师傅按格子摆
// south.add(...) 四样
frame.add(north, BorderLayout.NORTH); // 整块板子上岗
frame.add(south, BorderLayout.CENTER);
frame.setVisible(true); // 永远最后
模板 2:事件绑定(装门铃)
btnOK.setEnabled(false); // 先灰着
cbAgree.addActionListener(e -> btnOK.setEnabled(cbAgree.isSelected())); // 勾了复活
btnOK.addActionListener(e -> {
String name = txtName.getText();
if (name.isEmpty()) {
JOptionPane.showMessageDialog(frame, "用户名不能为空!");
} else {
JOptionPane.showMessageDialog(frame, "欢迎你," + name + "!");
}
});
模板 3:密码与单选的红牌姿势
String pwd = new String(pwdField.getPassword()); // 不用过时的 getText()
ButtonGroup group = new ButtonGroup(); // 单选必须收编
group.add(rbMale); group.add(rbFemale);
boolean ok = rbMale.isSelected(); // 判断选没选
模板 4:JavaFX 最小骨架
public class Demo extends Application {
@Override
public void start(Stage stage) {
VBox root = new VBox(10, new Label("你好"), new Button("点我"));
stage.setScene(new Scene(root, 300, 200));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
四、GUI 五大名坑
窗口不出现,或出现了但组件没进去(组件还在往台上搬)。铁律:setVisible(true) 永远是搭建完后的最后一句。
默认 BorderLayout 全进中区,后到顶先到,"只剩最后一个"。要么指定区域,要么先打包进 JPanel(快递箱)。
过时 API(IDEA 划删除线)。用 getPassword() 返回 char[],要字符串 new String(pw)——数组用完可清零,密码不留常量池痕迹。
不 addActionListener 装门铃,点了等于没点。另外门铃是追加不是覆盖,装俩响俩;Lambda 里改局部变量编译不过(effectively final)。
必报 missing components——JDK 11 起 JavaFX 不内置。先装 OpenJFX(IDEA 加库 + VM 参数 --module-path ... --add-modules javafx.controls)。
五、收官暗线:GUI 没有新知识,全是老朋友上岗
回头翻翻,这一章的每个"新概念"都是老知识换了身衣服:
- 监听器 = 4.3 接口合同:ActionListener 是 JDK 写好的合同,你提供实现;
- 匿名内部类 → Lambda = 4.6 → 4.7 的老路,GUI 只是它们最大的施工现场;
- 面板打包/布局师傅 = 多态与组合思想:容器持有"能排版的东西",换师傅即换实现;
- UI 线程铁律 = 第十二章:界面只由 UI 线程摸,后台线程算完再交回;
- 密码存 char[] = 2.7 数组 + 6.2 常量池的联合应用;
- 毕业题里的 equals = 6.2 老规矩:字符串比较永远 equals。
Java 学到第十四章,"新章节"越来越薄、"老知识"越来越厚——这正是学明白的样子。
六、跨章连线
- 第四章 面向对象(下)/4.3 抽象类和接口:监听器合同、EventHandler 合同——接口是 GUI 的接线方式
- 第四章 面向对象(下)/4.7 函数式编程:Lambda 从练习场开进正式岗位,全章默认写法
- 第六章 Java API/6.2 字符串类:equals 比较、字符串不可变、常量池与密码 char[]
- 第十二章 多线程/12.1 进程与线程:UI 线程铁律的出处,sleep/后台任务进阶时的规矩
- 第二章 Java编程基础/2.7 数组:getPassword 返回 char[] 的老朋友
七、毕业大题:完整登录注册窗(GUI 全章总装)
需求:窗口分三区——北区用户名+密码( GridLayout 对齐),南区协议勾选+登录按钮;未勾协议按钮灰色,点了校验:为空弹警告,用户名 admin 且密码 123456 弹欢迎,否则弹"用户名或密码错误"。
import javax.swing.*;
import java.awt.*;
public class FinalGUI {
public static void main(String[] args) {
JFrame frame = new JFrame("登录");
frame.setSize(360, 220);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel center = new JPanel(new GridLayout(2, 2, 5, 5)); // 14.3 网格对齐
center.add(new JLabel("用户名"));
JTextField txtName = new JTextField(15);
center.add(txtName);
center.add(new JLabel("密码"));
JPasswordField pwd = new JPasswordField(15);
center.add(pwd);
JCheckBox cbAgree = new JCheckBox("我同意用户协议"); // 14.2 组件
JButton btnLogin = new JButton("登录");
btnLogin.setEnabled(false);
JPanel south = new JPanel();
south.add(cbAgree);
south.add(btnLogin);
cbAgree.addActionListener(e -> btnLogin.setEnabled(cbAgree.isSelected())); // 14.4 门铃
btnLogin.addActionListener(e -> {
String name = txtName.getText();
String password = new String(pwd.getPassword()); // 14.2 红牌姿势
if (name.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(frame, "用户名和密码不能为空!"); // 14.1 弹窗
} else if ("admin".equals(name) && "123456".equals(password)) {
JOptionPane.showMessageDialog(frame, "登录成功,欢迎回来!");
} else {
JOptionPane.showMessageDialog(frame, "用户名或密码错误!");
}
});
frame.add(center, BorderLayout.CENTER);
frame.add(south, BorderLayout.SOUTH);
frame.setVisible(true);
}
}
- 开窗五步齐了吗?setVisible 是不是最后一句?
- 密码走 getPassword() 转 String 了吗?
- 单选/复选需要互斥的收编 ButtonGroup 了吗?
- 每个要"活"的组件都装门铃了吗?
- 字符串比较全用 equals 了吗?
- 板子(JPanel)打包再上岗了吗?
答不上来的,回 14.1~14.5 对应节回炉。
八、下一步学什么
- ☑ 15.1 项目开发准备 ✅ —— 点此复习:CRM 需求分析与功能清单、三层类蓝图(View/List/Customer + CMUtility)、Demo31 四类骨架跑通
- ☐ 15.2(按教材顺序) —— 报个标题接着走。等你报标题。
相关笔记
- 第十四章 图形用户界面/14.1 Swing概述 · 第十四章 图形用户界面/14.2 Swing的常见组件 · 第十四章 图形用户界面/14.3 布局管理器 · 第十四章 图形用户界面/14.4 事件处理机制 · 第十四章 图形用户界面/14.5 JavaFX(本章五节回看入口)
- 第四章 面向对象(下)/4.7 函数式编程:本章出勤率最高的老朋友