Java Swing 编程全面解析:从 AWT 到 Swing 的进化之路
目录
前言
一、AWT 简介
1. 什么是 AWT?
2. AWT 的基本组件
3. AWT 编程示例
二、Swing 的诞生与进化
1. Swing 的特点
2. Swing 和 AWT 的主要区别
3. Swing 的基本组件
三、Swing 编程的基础示例
四、Swing 的高级功能
1. 布局管理器
2. 事件监听
3. 自定义外观
五、综合案例:计算器
六、总结
前言
Java 提供了强大的图形用户界面(GUI)工具,用于创建跨平台的桌面应用程序。从早期的 AWT(Abstract Window Toolkit)到更先进的 Swing,Java GUI 编程逐步演进,解决了跨平台一致性、组件丰富性以及性能等问题。本篇博客将详细讲解从 AWT 到 Swing 的过渡。
一、AWT 简介
1. 什么是 AWT?
AWT(Abstract Window Toolkit)是 Java 1.0 提供的一个 GUI 工具包,它使用系统的本地 GUI 组件(如 Windows 的按钮、macOS 的窗口等)来构建界面。由于 AWT 依赖于本地操作系统的组件,因此具有如下特点:
- 优点:
- 跨平台支持:能在不同操作系统中运行。
- 轻量级:组件直接调用本地系统资源。
- 缺点:
- 限制较多:组件功能单一,难以满足复杂 GUI 的需求。
- 外观不一致:不同操作系统上的显示效果可能不同。
- 不灵活:自定义组件的能力有限。
2. AWT 的基本组件
AWT 提供了一些基本组件,例如:
- Container:顶级容器(如
Frame
、Panel
)用于容纳其他组件。 - Component:基本组件(如
Button
、Label
、TextField
)。 - Layout Manager:布局管理器,用于控制组件的排列方式。
3. AWT 编程示例
import java.awt.*;public class AWTExample {public static void main(String[] args) {// 创建 Frame 窗口Frame frame = new Frame("AWT Example");frame.setSize(300, 200);frame.setLayout(new FlowLayout());// 添加组件Label label = new Label("AWT Label");Button button = new Button("Click Me");frame.add(label);frame.add(button);// 显示窗口frame.setVisible(true);}
}
二、Swing 的诞生与进化
为了弥补 AWT 的不足,Java 在 JDK 1.2 中引入了 Swing。Swing 是基于 AWT 的扩展,它不仅解决了 AWT 的缺陷,还大大增强了 GUI 开发的能力。
1. Swing 的特点
- 轻量级组件:Swing 的组件不依赖于本地操作系统,而是用纯 Java 实现。
- 丰富的组件库:提供了大量高级组件(如
JTable
、JTree
、JTabbedPane
等),能够满足复杂的用户界面需求。 - 可定制性:Swing 支持基于
Pluggable Look-and-Feel
的外观定制,可以实现跨平台一致的用户界面。 - 事件驱动模型:通过事件监听器机制处理用户交互。
2. Swing 和 AWT 的主要区别
特性 | AWT | Swing |
---|---|---|
组件实现 | 依赖本地操作系统的组件 | 纯 Java 实现(轻量级组件) |
组件外观 | 外观由操作系统决定 | 支持跨平台外观,可自定义 |
线程模型 | 非线程安全 | 大多数操作需要在事件调度线程中完成 |
组件种类 | 基本组件,如 Button 、Label | 丰富组件,如 JButton 、JLabel |
功能扩展性 | 功能有限,扩展困难 | 支持高级功能,易于扩展 |
3. Swing 的基本组件
Swing 的组件以 J
开头,例如:
- 顶级容器:
JFrame
、JDialog
、JApplet
。 - 基本组件:
JButton
、JLabel
、JTextField
、JCheckBox
。 - 高级组件:
JTable
、JTree
、JTabbedPane
、JScrollPane
。
三、Swing 编程的基础示例
以下是一个使用 Swing 创建简单窗口的示例:
import javax.swing.*;public class SwingExample {public static void main(String[] args) {// 创建 JFrame 窗口JFrame frame = new JFrame("Swing Example");frame.setSize(300, 200);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 添加组件JLabel label = new JLabel("Hello, Swing!");JButton button = new JButton("Click Me");frame.setLayout(new java.awt.FlowLayout());frame.add(label);frame.add(button);// 显示窗口frame.setVisible(true);}
}
四、Swing 的高级功能
1. 布局管理器
Swing 提供了多种布局管理器,用于控制组件在容器中的排列方式:
- FlowLayout:按添加顺序从左到右排列。
- BorderLayout:分为东、南、西、北、中五个区域。
- GridLayout:以网格形式排列组件。
- BoxLayout:允许组件在垂直或水平方向排列。
frame.setLayout(new BorderLayout());
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 JButton("Center"), BorderLayout.CENTER);
2. 事件监听
Swing 使用事件监听器来处理用户操作,例如按钮点击、鼠标移动等。
示例:按钮点击事件
button.addActionListener(e -> System.out.println("Button clicked!"));
3. 自定义外观
Swing 支持修改外观(Look-and-Feel),可以通过以下代码设置跨平台外
try {UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e) {e.printStackTrace();
}
五、综合案例:计算器
以下是一个简单的 Swing 计算器示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;public class Calculator {public static void main(String[] args) {JFrame frame = new JFrame("Calculator");frame.setSize(400, 500);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setLayout(new BorderLayout());// 显示区域JTextField display = new JTextField();display.setFont(new Font("Arial", Font.BOLD, 24));frame.add(display, BorderLayout.NORTH);// 按钮区域JPanel buttonPanel = new JPanel();buttonPanel.setLayout(new GridLayout(4, 4));String[] buttons = {"7", "8", "9", "/","4", "5", "6", "*","1", "2", "3", "-","C", "0", "=", "+"};for (String text : buttons) {JButton button = new JButton(text);button.setFont(new Font("Arial", Font.BOLD, 20));buttonPanel.add(button);// 按钮事件监听button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String command = e.getActionCommand();if (command.equals("=")) {// 计算结果try {display.setText(evaluateExpression(display.getText()));} catch (Exception ex) {display.setText("Error");}} else if (command.equals("C")) {// 清空输入框display.setText("");} else {// 更新显示display.setText(display.getText() + command);}}});}frame.add(buttonPanel, BorderLayout.CENTER);// 显示窗口frame.setVisible(true);}// 方法:计算输入的数学表达式private static String evaluateExpression(String expression) {// 使用栈进行数学表达式的求值Stack<Double> values = new Stack<>();Stack<Character> operators = new Stack<>();// 处理输入的表达式for (int i = 0; i < expression.length(); i++) {char ch = expression.charAt(i);// 跳过空格if (ch == ' ') continue;// 如果是数字,处理多位数if (Character.isDigit(ch)) {StringBuilder num = new StringBuilder();while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {num.append(expression.charAt(i));i++;}i--; // 回退一个字符values.push(Double.parseDouble(num.toString()));} // 如果是左括号,压入栈else if (ch == '(') {operators.push(ch);} // 如果是右括号,解决括号中的内容else if (ch == ')') {while (operators.peek() != '(') {values.push(applyOperation(operators.pop(), values.pop(), values.pop()));}operators.pop(); // 弹出 '('} // 如果是运算符,处理优先级并执行运算else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {while (!operators.isEmpty() && hasPrecedence(ch, operators.peek())) {values.push(applyOperation(operators.pop(), values.pop(), values.pop()));}operators.push(ch);}}// 处理剩下的运算符while (!operators.isEmpty()) {values.push(applyOperation(operators.pop(), values.pop(), values.pop()));}// 最终结果return String.valueOf(values.pop());}// 方法:检查当前运算符的优先级private static boolean hasPrecedence(char op1, char op2) {if (op2 == '(' || op2 == ')') return false;return (op1 != '*' && op1 != '/') || (op2 != '+' && op2 != '-');}// 方法:执行基本的算术运算private static double applyOperation(char op, double b, double a) {switch (op) {case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/': if (b == 0) throw new UnsupportedOperationException("Cannot divide by zero");return a / b;}return 0;}
}
后续会模拟一个跟手机差不多的计算器。
六、总结
Java Swing 的出现极大地提升了 Java GUI 编程的能力,它克服了 AWT 的局限,提供了更强大的组件库和更高的灵活性。在实际开发中,Swing 仍然是构建桌面应用程序的常用工具,尽管随着 JavaFX 的发展,Swing 的使用场景有所减少,但依然是学习 Java GUI 编程的良好起点。