☕ 第十四章 图形用户界面

14.2 Swing的常见组件

📄 一句话概括

上一节会开窗口了,这一节把能摆进窗口的家伙们认全:文本家族(标签/输入框/密码框/多行框)、按钮家族(按钮/复选/单选)、选择家族(下拉/列表)——组件的用法高度统一:setText 摆内容、getText 拿内容、setEnabled 管死活。本节组件还是"死的",14.3 装上监听才活。


一、组件也讲"家族":先分类再记名

Swing 常用组件十来个,死记硬背容易乱——按长得像、干得像分三大家族,一个家族一桌:

家族 组件 一句话职责
文本家族 JLabel 标签,只显示字,不收输入
JTextField 单行输入框(用户名、搜索框)
JPasswordField 密码框,输啥都显示 ●
JTextArea 多行文本域(简介、留言板)
按钮家族 JButton 按钮,点了干活(逻辑在 14.3)
JCheckBox 复选框,可多选(兴趣爱好)
JRadioButton 单选按钮,必须配 ButtonGroup 才互斥
选择家族 JComboBox 下拉框(选省份、选年份)
JList 列表框,一列选项摊开给你挑

记法:类名前缀 J = Swing 组件(14.1 的家谱),后缀就是它的人设——PasswordField 管密码,ComboBox 是"可编辑的下拉"。

二、通用三板斧:一半的方法不用背

组件再多,高频操作就三个,几乎所有组件通用:

txtName.setText("波仔");       // 摆内容进去(输入框、标签都能用)
String name = txtName.getText(); // 拿用户输的内容(返回 String)
btnOK.setEnabled(false);        // 禁用:变灰、点不动(true 恢复)

把这三个练熟,一半的组件 API 已经到手。

三、文本家族:四个框,一个红牌

JLabel lbl = new JLabel("用户名:");          // 标签:只显示
JTextField txt = new JTextField(15);          // 单行:15 列宽
JPasswordField pwd = new JPasswordField(15);  // 密码:显示 ●
JTextArea area = new JTextArea(4, 15);        // 多行:4 行 15 列
🚨 红牌坑:getPassword() 返回 char[]

拿密码框内容不能用 getText()(官方标记过时),要用:

char[] pw = pwd.getPassword();          // 返回字符数组,不是 String!
String s = new String(pw);              // 想按字符串用,先包一层

返回值类型是 char[]——数组那章(2.7)的老朋友。为什么这么设计?字符串在内存里长期赖着不走(6.2 常量池),数组用完可以清零,密码不留痕更安全。新手记住结论即可:密码框用 getPassword(),转 new String(...)。

四、按钮家族:复选天生自由,单选必须收编

JCheckBox cbAgree = new JCheckBox("我同意协议");
JCheckBox cbEmail = new JCheckBox("订阅邮件");      // 两个复选互不干扰

JRadioButton rbMale = new JRadioButton("男");
JRadioButton rbFemale = new JRadioButton("女");
ButtonGroup group = new ButtonGroup();   // 1. 造一个"单选组"
group.add(rbMale);                       // 2. 把按钮收编进组
group.add(rbFemale);                     //    收编后才互斥!
⚠️ ButtonGroup 只管互斥,不管摆放

它是个"看不见的管理员":只负责让组内按钮互斥,不负责把它们摆到界面上。摆位置还是老老实实 add 进面板。忘了 add,按钮就真没了;只 add 忘了收编,两个单选能同时亮。

判断选没选:isSelected() 返回 boolean;代码代勾:setSelected(true)。

五、选择家族:JComboBox 下拉框

JComboBox<String> box = new JComboBox<>();
box.addItem("湖北省");
box.addItem("湖南省");
box.addItem("广东省");
Object item = box.getSelectedItem();   // 拿选中的项,返回 Object
String province = (String) item;       // 想按 String 用,强转(4.4 的老账)

选项在运行时动态添加(addItem),取值 getSelectedItem() 返回 Object——和 9.3 反射造对象、10.5 读对象一个套路:容器不知道里面装的啥,取出来你自己认。

六、动手:Demo27 注册表单(静态版)

import javax.swing.*;

public class Demo27 {
    public static void main(String[] args) {
        JFrame frame = new JFrame("注册新账号");
        frame.setSize(360, 280);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel lblName = new JLabel("用户名");
        JTextField txtName = new JTextField(12);
        JLabel lblPwd = new JLabel("密码");
        JPasswordField pwd = new JPasswordField(12);
        JCheckBox cbAgree = new JCheckBox("我同意注册协议");
        JButton btnOK = new JButton("注册");
        btnOK.setEnabled(false);              // 协议没勾,先灰掉

        JPanel panel = new JPanel();          // 面板:先把组件都装进板子
        panel.add(lblName);
        panel.add(txtName);
        panel.add(lblPwd);
        panel.add(pwd);
        panel.add(cbAgree);
        panel.add(btnOK);
        frame.add(panel);                     // 板子再进窗口

        frame.setVisible(true);
    }
}

跑起来:窗口里整整齐齐摆着用户名、密码、协议勾选和灰色的注册按钮——虽然点注册还没反应,但"脸"已经搭完了。怎么让勾了协议按钮变亮、点了注册弹窗提示,就是 14.3 事件监听的戏。

💡 实验后再回来学"摆放"

Demo27 里组件是按 add 顺序一行流排的,想摆成"标签左、输入框右"的表格样子,要靠布局管理器(setLayout)——本节只认识这个词,具体下节展开。

七、动手实验(3 个 × 30 秒)

🧪 实验 1:两个单选按钮不收编会怎样

造两个 JRadioButton,直接 add 进面板(不进 ButtonGroup):两个能同时选中——单选按钮名不副实,收编才互斥。

🧪 实验 2:按钮 setEnabled(false) 长什么样

把 Demo27 里 btnOK.setEnabled(false) 那行的 false 改 true 再对比:false 时按钮灰字、鼠标点上去没任何反馈。这就是"协议未同意"的标准交互。

🧪 实验 3:密码框错用 getText()

对 JPasswordField 调 getText():编译通过但划删除线(过时 API 警告),IDEA 会提示改用 getPassword()。跟着提示走,顺手看一眼返回值类型——char[]。

八、五个常见误区

⚠️ 误区 1:密码框用 getText()

过时 API(有删除线警告),正确姿势 getPassword() 返回 char[],要字符串就 new String(pw)。

⚠️ 误区 2:单选按钮忘收编进 ButtonGroup

不收编 = 各选各的,两个 JRadioButton 能同时亮。group.add(rb) 一个都不能少。

⚠️ 误区 3:以为 ButtonGroup 会帮忙摆放

它只管互斥。组件上屏永远靠 add,ButtonGroup 加不加都不影响显示。

⚠️ 误区 4:getSelectedItem() 直接当 String 用

返回 Object,要 (String) 强转——直接赋值给 String 编译都不过(4.4 的老规矩)。

⚠️ 误区 5:组件 add 了却看不见

检查两件事:①add 到窗口的内容面板/板子上了吗;②窗口 setVisible(true) 了吗。组件和窗口,谁没上台谁隐身。

九、自测题

❓ Q1:三大家族各有哪些组件?各挑一个说职责。

文本家族:JLabel 只显示 / JTextField 单行 / JPasswordField 密码● / JTextArea 多行;按钮家族:JButton 点击干活 / JCheckBox 多选 / JRadioButton 单选;选择家族:JComboBox 下拉 / JList 列表。

❓ Q2:通用三板斧是哪三个方法?

setText() 摆内容、getText() 拿内容、setEnabled(false) 禁用置灰。绝大多数组件通用。

❓ Q3:JPasswordField 拿内容用什么方法?返回什么类型?

getPassword(),返回 char[] 不是 String——设计原因是密码用完可清零、不留常量池痕迹;要 String 就 new String(pw)。

❓ Q4:JRadioButton 为什么能同时选中两个?怎么治?

没收编进 ButtonGroup 就各自为政。group.add(rb) 把它们收进同一个组,组内自动互斥;但 ButtonGroup 不管摆放,上屏仍要 add。

❓ Q5:(毕业题)把 Demo27 升级成"静态注册表单完整版":加性别单选(男女互斥)、省份下拉(湖北/湖南/广东)、多行简介框,注册按钮保持灰色。

参考骨架:

JRadioButton rbM = new JRadioButton("男");
JRadioButton rbF = new JRadioButton("女");
ButtonGroup g = new ButtonGroup();
g.add(rbM); g.add(rbF);
JComboBox<String> box = new JComboBox<>();
box.addItem("湖北省"); box.addItem("湖南省"); box.addItem("广东省");
JTextArea area = new JTextArea(3, 12);
panel.add(rbM); panel.add(rbF); panel.add(box); panel.add(area);

自检:单选收编了吗?下拉的泛型 <String> 写了吗?按钮还是灰的吗?——界面搭完,就差让它"活"了。

十、下一步学什么


相关笔记