☕ 第十四章 图形用户界面

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 五大名坑

⚠️ 坑 1:setVisible 忘了调或不放最后

窗口不出现,或出现了但组件没进去(组件还在往台上搬)。铁律:setVisible(true) 永远是搭建完后的最后一句。

⚠️ 坑 2:往 JFrame 直接 add 一堆组件

默认 BorderLayout 全进中区,后到顶先到,"只剩最后一个"。要么指定区域,要么先打包进 JPanel(快递箱)。

⚠️ 坑 3:密码框用 getText()

过时 API(IDEA 划删除线)。用 getPassword() 返回 char[],要字符串 new String(pw)——数组用完可清零,密码不留常量池痕迹。

⚠️ 坑 4:以为按钮天生点了有反应

不 addActionListener 装门铃,点了等于没点。另外门铃是追加不是覆盖,装俩响俩;Lambda 里改局部变量编译不过(effectively final)。

⚠️ 坑 5:JDK 17 直接跑 JavaFX

必报 missing components——JDK 11 起 JavaFX 不内置。先装 OpenJFX(IDEA 加库 + VM 参数 --module-path ... --add-modules javafx.controls)。

五、收官暗线:GUI 没有新知识,全是老朋友上岗

回头翻翻,这一章的每个"新概念"都是老知识换了身衣服:

Java 学到第十四章,"新章节"越来越薄、"老知识"越来越厚——这正是学明白的样子。

六、跨章连线

七、毕业大题:完整登录注册窗(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);
    }
}
❓ 自检清单(全对才算毕业)
  1. 开窗五步齐了吗?setVisible 是不是最后一句?
  2. 密码走 getPassword() 转 String 了吗?
  3. 单选/复选需要互斥的收编 ButtonGroup 了吗?
  4. 每个要"活"的组件都装门铃了吗?
  5. 字符串比较全用 equals 了吗?
  6. 板子(JPanel)打包再上岗了吗?

答不上来的,回 14.1~14.5 对应节回炉。

八、下一步学什么


相关笔记