前言
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() {
@Override
public 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 编程的良好起点。