目录
- 核心概念:Swing 的基本组成
- 第一个 Swing 程序:Hello World
- 常用 Swing 组件详解
- 布局管理器
- 事件处理
- 高级特性
- 开发工具推荐
- 总结与学习路径
核心概念:Swing 的基本组成
在开始编码前,需要理解几个核心概念:
a) 组件
Swing 应用程序是由各种“组件”构建的,组件是屏幕上能看得见、能交互的元素。
- 顶层容器: 窗口本身,是所有其他组件的“家”,主要有三个:
JFrame: 带有标题栏、边框和最大化/最小化/关闭按钮的主窗口。几乎所有 Swing 应用都始于一个 JFrame。JDialog: 一个对话框窗口,通常用于临时交互。JApplet: 已过时,不推荐使用。
- 轻量级组件: Swing 中的所有组件(以
J开头,如JButton,JLabel)都是轻量级的,这意味着它们不依赖本地操作系统的 GUI 元素,而是由 Java 自己绘制,保证了外观的一致性。 - 重量级组件: AWT(Abstract Window Toolkit)中的一些组件(如
Button,Canvas),它们直接使用操作系统的 GUI 元素,在 Swing 中应尽量避免混合使用。
b) 容器
容器是一种特殊的组件,它可以“容纳”其他组件。
JFrame本身就是一个容器,但它的内容不能直接添加到JFrame实例上,必须先获取它的内容面板。JPanel: 最常用、最通用的容器,它本身没有特殊的边框或标题,通常用于对其他组件进行分组和布局。
c) 布局管理器
布局管理器负责决定容器内的组件如何排列、定位和调整大小。绝对坐标(setBounds(x, y, width, height))在 Swing 中很少使用,因为它们会使界面在不同屏幕分辨率下变得一团糟。
常见的布局管理器有:
BorderLayout: 将容器分为东、南、西、北、中五个区域。FlowLayout: 从左到右、从上到下地排列组件,像文字一样。GridLayout: 创建一个网格,所有单元格大小相同。GridBagLayout: 最强大也最复杂的布局,可以创建非常灵活的网格。BoxLayout: 允许组件在垂直或水平方向上依次排列。
第一个 Swing 程序:Hello World
这是一个最简单的 Swing 应用,它创建一个窗口并显示一个标签。
import javax.swing.*; // 导入所有 Swing 组件
public class HelloWorldSwing {
public static void main(String[] args) {
// Swing 的 GUI 操作应该在事件分发线程 上执行
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// 1. 创建顶层容器 JFrame
JFrame frame = new JFrame("Hello, Swing World!");
// 2. 设置窗口关闭时的默认操作 (退出程序)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 3. 创建一个组件 (例如一个标签)
JLabel label = new JLabel("Hello, Swing!", SwingConstants.CENTER);
// 4. 将组件添加到 JFrame 的内容面板 中
frame.getContentPane().add(label);
// 5. 设置窗口大小 (像素)
frame.setSize(300, 200);
// 6. 让窗口在屏幕上可见
frame.setVisible(true);
}
});
}
}
代码解释:
SwingUtilities.invokeLater(...): 这是启动任何 Swing 应用程序的标准方式,它确保所有的 GUI 创建和更新都在 EDT 上完成,避免了线程安全问题。JFrame frame = new JFrame(...): 创建一个窗口实例,并设置标题。frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE): 至关重要! 如果不设置,点击窗口的关闭按钮只会隐藏窗口,而程序的后台线程仍在运行。EXIT_ON_CLOSE会完全终止 Java 虚拟机。JLabel: 一个简单的、用于显示文本或图像的组件。frame.getContentPane().add(label):JFrame的getContentPane()方法返回其内容面板,我们将JLabel添加到这个面板上。frame.setSize(...): 设置窗口的初始尺寸。frame.setVisible(true): 将窗口设置为可见,在调用此方法之前,窗口是不可见的。
常用 Swing 组件详解
下面是一些最常用的组件,通常放在 JPanel 中,然后将 JPanel 添加到 JFrame。
| 组件 | 类名 | 用途 | 示例 |
|---|---|---|---|
| 按钮 | JButton |
触发一个动作 | new JButton("点击我"); |
JLabel |
显示文本或图像 | new JLabel("用户名:"); |
|
| 文本框 | JTextField |
单行文本输入 | new JTextField(20); (20是列数) |
| 密码框 | JPasswordField |
单行密码输入,显示为掩码 | new JPasswordField(); |
| 文本区域 | JTextArea |
多行文本显示和编辑 | new JTextArea(5, 20); (5行, 20列) |
| 复选框 | JCheckBox |
开关选项,可多选 | new JCheckBox("记住我"); |
| 单选按钮 | JRadioButton |
互斥选项,需与 ButtonGroup 配合使用 |
new JRadioButton("男"); |
| 下拉列表 | JComboBox |
从下拉列表中选择一项 | new JComboBox<>(new String[]{"A", "B", "C"}); |
| 列表 | JList |
显示一个可滚动的项目列表 | new JList<>(new String[]{"苹果", "香蕉", "橙子"}); |
| 表格 | JTable |
以二维表格形式显示数据 | new JTable(data, columnNames); |
| 树 | JTree |
以分层结构显示数据 | new JTree(topNode); |
布局管理器实例
理解布局管理器是创建美观界面的关键。
a) BorderLayout (默认布局)
JFrame frame = new JFrame("BorderLayout Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(5, 5)); // 水平间距5, 垂直间距5
frame.add(new JButton("North"), BorderLayout.NORTH);
frame.add(new JButton("South"), BorderLayout.SOUTH);
frame.add(new JButton("East"), BorderLayout.EAST);
frame.add(new JButton("West"), BorderLayout.WEST);
frame.add(new JLabel("Center Area"), BorderLayout.CENTER);
frame.setSize(400, 300);
frame.setVisible(true);
b) FlowLayout
JFrame frame = new JFrame("FlowLayout Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建一个使用 FlowLayout 的面板
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 20)); // 左对齐, 水平间距10, 垂直间距20
panel.add(new JButton("Button 1"));
panel.add(new JButton("Button 2"));
panel.add(new JButton("A Longer Button 3"));
frame.add(panel);
frame.pack(); // pack() 方法会自动调整窗口大小以适应其内容
frame.setVisible(true);
c) GridLayout
JFrame frame = new JFrame("GridLayout Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 3行3列的网格,间距为5
JPanel panel = new JPanel(new GridLayout(3, 3, 5, 5));
for (int i = 1; i <= 9; i++) {
panel.add(new JButton("Button " + i));
}
frame.add(panel);
frame.pack();
frame.setVisible(true);
事件处理
Swing 使用监听器模式来处理用户交互(如点击按钮、输入文本)。
核心思想:
- 事件源: 发生事件的组件(如
JButton)。 - 事件: 描述发生了什么事情的对象(如
ActionEvent,表示按钮被点击)。 - 监听器: 一个实现了特定监听器接口(如
ActionListener)的对象,它“监听”事件源,并在事件发生时执行相应代码。
示例:为按钮添加点击事件
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ButtonEventDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("事件处理示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton myButton = new JButton("点击我");
JLabel statusLabel = new JLabel("等待点击...");
// 1. 创建监听器 (匿名内部类方式)
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 当按钮被点击时,此方法会被调用
statusLabel.setText("按钮被点击了!");
System.out.println("按钮在事件处理中被点击了。");
}
};
// 2. 将监听器注册到事件源 (按钮)
myButton.addActionListener(listener);
frame.add(myButton);
frame.add(statusLabel);
frame.pack();
frame.setVisible(true);
});
}
}
更现代的写法:Lambda 表达式 (Java 8+)
上面的匿名内部类可以用更简洁的 Lambda 表达式代替:
// 将第1、2步合并
myButton.addActionListener(e -> {
statusLabel.setText("按钮被点击了!");
System.out.println("按钮在Lambda中被点击了。");
});
e -> { ... } ActionListener 接口中 actionPerformed 方法的一个简写形式。
高级特性
-
MVC (Model-View-Controller) 模式:
- Swing 本身就采用了 MVC 的变种(称为 Model-Delegate 或 Separable Model)。
- Model (模型): 存储数据的状态。
JButton的模型是ButtonModel,它记录了按钮是否被按下、是否被选中、是否启用等状态。 - View (视图): 负责显示数据,这就是你看到的
JButton、JLabel等组件。 - Controller (控制器): 处理用户输入,并更新模型,监听器(如
ActionListener)就扮演了控制器的角色。
-
自定义绘制:
- 当默认组件无法满足需求时(如画一个自定义的图表或游戏),你可以继承
JComponent或JPanel,并重写其paintComponent(Graphics g)方法。 - 重要: 始终先调用
super.paintComponent(g);,以确保组件的背景等被正确绘制。
- 当默认组件无法满足需求时(如画一个自定义的图表或游戏),你可以继承
-
多线程与 Swing:
- 再次强调:所有 GUI 操作(创建、更新、修改组件)都必须在事件分发线程 上执行。
- 对于耗时操作(如网络请求、文件读写),绝对不能在 EDT 中执行,否则界面会“冻结”(无响应)。
- 正确做法:启动一个后台线程(
SwingWorker是最佳选择)来执行耗时任务,完成后通过SwingUtilities.invokeLater将结果更新到界面。
开发工具推荐
- IDE (集成开发环境):
- IntelliJ IDEA: 强大的代码提示、重构和 GUI 设计器(插件)。
- Eclipse: 拥有成熟的 Visual Editor 插件,可以拖拽式创建界面。
- NetBeans: 内置了非常优秀的 Matisse GUI 设计器,非常适合初学者可视化地构建界面。
- GUI 设计器:
可以通过拖拽组件来生成 Swing 代码,大大提高开发效率,但理解手动编码的原理仍然非常重要。
总结与学习路径
- 掌握基础: 从
JFrame开始,理解组件、容器和布局管理器,能独立创建简单的窗口并排列组件。 - 熟悉组件: 熟练使用
JButton,JTextField,JLabel,JTextArea,JComboBox等常用组件。 - 精通事件处理: 深刻理解监听器模式,能够为各种组件添加事件响应,特别是熟练使用 Lambda 表达式。
- 学习高级布局: 掌握
GridBagLayout,它是创建复杂、专业界面的利器。 - 探索高级主题: 了解 MVC 模式在 Swing 中的应用,学习如何进行自定义绘制和如何正确处理多线程问题。
- 实践: 尝试开发一个完整的小应用,如一个简单的记事本、一个待办事项列表或一个计算器,这是巩固知识的最好方式。
Swing 虽然看起来有些“古老”,但其设计思想非常经典,学习它对于理解任何 GUI 框架都大有裨益,祝你学习愉快!
