跳到主要内容

Java Swing

什么是 Java Swing?

Java Swing 是 Java 基础类库(JFC)的一部分,提供了一套丰富的图形用户界面(GUI)组件,使开发者能够创建跨平台的桌面应用程序。Swing 是对早期 AWT(Abstract Window Toolkit)的改进和扩展,它提供了更多的组件选择,并且完全用 Java 代码实现,保证了跨平台的一致性。

备注

Swing 的设计遵循 MVC(Model-View-Controller)架构模式,将数据、用户界面和业务逻辑分离,使代码更加模块化和易于维护。

Swing 的优势

  • 跨平台性:编写一次,到处运行
  • 可定制性:支持自定义外观和感觉(Look and Feel)
  • 轻量级:Swing 组件是纯 Java 实现的,不依赖于本地窗口系统
  • 丰富的组件库:提供了大量预制组件
  • 事件驱动编程:基于监听器模式处理用户交互

开始使用 Swing

基本设置

要使用 Swing,首先需要导入相关包:

java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

创建第一个 Swing 窗口

下面是一个创建简单 Swing 窗口的例子:

java
import javax.swing.*;

public class HelloSwing {
public static void main(String[] args) {
// 创建在 Event Dispatch Thread 中运行 GUI 代码
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// 创建窗口
JFrame frame = new JFrame("我的第一个 Swing 应用");

// 设置窗口大小
frame.setSize(300, 200);

// 设置关闭操作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 居中显示
frame.setLocationRelativeTo(null);

// 显示窗口
frame.setVisible(true);
}
});
}
}

这段代码创建了一个标题为"我的第一个 Swing 应用"的窗口,大小为 300x200 像素。程序运行后,窗口将在屏幕中央显示。

提示

总是使用 SwingUtilities.invokeLater() 来创建和更新 Swing 组件,这能确保所有 GUI 操作都在专门的 Event Dispatch Thread 中执行,避免线程问题。

Swing 基础组件

Swing 提供了丰富的 UI 组件,以下是一些常用的基础组件:

标签(JLabel)

用于显示文本或图像:

java
JLabel label = new JLabel("这是一个标签");
frame.add(label);

按钮(JButton)

用户可点击的按钮:

java
JButton button = new JButton("点击我");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "你点击了按钮!");
}
});
frame.add(button);

文本框(JTextField)

单行文本输入框:

java
JTextField textField = new JTextField(20); // 宽度为20个字符
frame.add(textField);

文本区域(JTextArea)

多行文本输入区:

java
JTextArea textArea = new JTextArea(5, 20); // 5行,每行20个字符
JScrollPane scrollPane = new JScrollPane(textArea); // 添加滚动功能
frame.add(scrollPane);

复选框(JCheckBox)

允许用户选择或取消选择项目:

java
JCheckBox checkBox = new JCheckBox("同意条款");
frame.add(checkBox);

单选按钮(JRadioButton)

允许用户从一组选项中选择一个:

java
JRadioButton option1 = new JRadioButton("选项 1");
JRadioButton option2 = new JRadioButton("选项 2");

// 创建一个按钮组,确保只能选择一个选项
ButtonGroup group = new ButtonGroup();
group.add(option1);
group.add(option2);

JPanel panel = new JPanel();
panel.add(option1);
panel.add(option2);
frame.add(panel);

布局管理

Swing 提供了多种布局管理器,用于控制组件在容器中的位置和大小:

FlowLayout

组件按照添加顺序从左到右、从上到下排列:

java
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());

frame.add(new JButton("按钮 1"));
frame.add(new JButton("按钮 2"));
frame.add(new JButton("按钮 3"));

BorderLayout

将容器分为东、西、南、北和中心五个区域:

java
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());

frame.add(new JButton("北"), BorderLayout.NORTH);
frame.add(new JButton("南"), BorderLayout.SOUTH);
frame.add(new JButton("东"), BorderLayout.EAST);
frame.add(new JButton("西"), BorderLayout.WEST);
frame.add(new JButton("中心"), BorderLayout.CENTER);

GridLayout

将容器分割成等大的网格:

java
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(3, 2)); // 3行2列

frame.add(new JButton("1"));
frame.add(new JButton("2"));
frame.add(new JButton("3"));
frame.add(new JButton("4"));
frame.add(new JButton("5"));
frame.add(new JButton("6"));

事件处理

Swing 使用事件监听器模式处理用户交互。以下是添加按钮点击事件的示例:

java
JButton button = new JButton("点击我");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击!");
}
});

使用 Java 8 lambda 表达式可以简化代码:

java
JButton button = new JButton("点击我");
button.addActionListener(e -> System.out.println("按钮被点击!"));

菜单创建

Swing 可以轻松创建菜单栏、菜单和菜单项:

java
// 创建菜单栏
JMenuBar menuBar = new JMenuBar();

// 创建文件菜单
JMenu fileMenu = new JMenu("文件");
JMenuItem openItem = new JMenuItem("打开");
JMenuItem saveItem = new JMenuItem("保存");
JMenuItem exitItem = new JMenuItem("退出");

fileMenu.add(openItem);
fileMenu.add(saveItem);
fileMenu.addSeparator(); // 添加分隔线
fileMenu.add(exitItem);

// 创建编辑菜单
JMenu editMenu = new JMenu("编辑");
JMenuItem cutItem = new JMenuItem("剪切");
JMenuItem copyItem = new JMenuItem("复制");
JMenuItem pasteItem = new JMenuItem("粘贴");

editMenu.add(cutItem);
editMenu.add(copyItem);
editMenu.add(pasteItem);

// 将菜单添加到菜单栏
menuBar.add(fileMenu);
menuBar.add(editMenu);

// 设置菜单栏
frame.setJMenuBar(menuBar);

// 添加事件监听
exitItem.addActionListener(e -> System.exit(0));

对话框

Swing 提供了多种对话框:

消息对话框

java
JOptionPane.showMessageDialog(
frame,
"这是一条信息消息",
"信息",
JOptionPane.INFORMATION_MESSAGE
);

确认对话框

java
int response = JOptionPane.showConfirmDialog(
frame,
"确定要执行此操作吗?",
"确认",
JOptionPane.YES_NO_OPTION
);

if (response == JOptionPane.YES_OPTION) {
System.out.println("用户选择了'是'");
} else {
System.out.println("用户选择了'否'");
}

输入对话框

java
String input = JOptionPane.showInputDialog(
frame,
"请输入您的姓名:"
);

if (input != null) {
System.out.println("输入的姓名是:" + input);
}

实际案例:简易计算器

下面是一个简易计算器的实现,展示了 Swing 在实际应用中的使用:

java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SimpleCalculator extends JFrame {
private JTextField display;
private double result = 0;
private String lastOperator = "=";
private boolean start = true;

public SimpleCalculator() {
// 设置窗口
setTitle("简易计算器");
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);

// 创建显示区域
display = new JTextField("0");
display.setEditable(false);
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);

// 创建按钮面板
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 4, 5, 5));

// 添加数字按钮
String[] buttonLabels = {
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
};

for (String label : buttonLabels) {
JButton button = new JButton(label);
buttonPanel.add(button);

if (Character.isDigit(label.charAt(0)) || label.equals(".")) {
button.addActionListener(new DigitButtonListener());
} else {
button.addActionListener(new OperatorButtonListener());
}
}

add(buttonPanel, BorderLayout.CENTER);

// 清除按钮
JButton clearButton = new JButton("清除");
clearButton.addActionListener(e -> {
start = true;
result = 0;
lastOperator = "=";
display.setText("0");
});
add(clearButton, BorderLayout.SOUTH);
}

private class DigitButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String digit = ((JButton)e.getSource()).getText();

if (start) {
display.setText(digit);
start = false;
} else {
display.setText(display.getText() + digit);
}
}
}

private class OperatorButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String operator = ((JButton)e.getSource()).getText();

if (!start) {
calculate();
start = true;
}

lastOperator = operator;
}
}

private void calculate() {
double x = Double.parseDouble(display.getText());

switch (lastOperator) {
case "+": result += x; break;
case "-": result -= x; break;
case "*": result *= x; break;
case "/": result /= x; break;
case "=": result = x; break;
}

display.setText(String.valueOf(result));
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new SimpleCalculator().setVisible(true);
});
}
}

运行这段代码,你会得到一个功能简单但实用的计算器应用程序。计算器包含数字按钮(0-9)、基本运算符按钮(+、-、*、/)以及等号和清除按钮。

Swing 的绘图功能

Swing 允许开发者通过重写 paintComponent() 方法来绘制自定义图形:

java
import javax.swing.*;
import java.awt.*;

public class DrawingExample extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

// 转换为 Graphics2D 以获得更多功能
Graphics2D g2d = (Graphics2D) g;

// 设置抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

// 绘制矩形
g2d.setColor(Color.BLUE);
g2d.fillRect(50, 50, 100, 70);

// 绘制圆形
g2d.setColor(Color.RED);
g2d.fillOval(200, 50, 100, 100);

// 绘制线条
g2d.setColor(Color.GREEN);
g2d.setStroke(new BasicStroke(3));
g2d.drawLine(50, 200, 300, 200);

// 绘制文本
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("Arial", Font.BOLD, 20));
g2d.drawString("Swing 绘图示例", 80, 250);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("绘图示例");
frame.add(new DrawingExample());
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

Swing 最佳实践

  1. 始终在 EDT 中工作:所有 Swing 组件的创建和更新都应在事件调度线程中完成。

    java
    SwingUtilities.invokeLater(() -> {
    // 创建和更新 Swing 组件的代码
    });
  2. 使用布局管理器:不要使用固定坐标定位组件,这会导致在不同平台上显示不一致。

  3. 合理组织组件:使用 JPanel 将相关组件分组,并为每个面板应用适当的布局管理器。

  4. 错误处理:捕获可能的异常并向用户显示友好的错误消息。

  5. 资源管理:及时释放不再使用的资源,如图像、文件句柄等。

总结

Java Swing 是一个强大而灵活的 GUI 工具包,虽然现在有更现代的 GUI 框架(如 JavaFX),但 Swing 因其简单性和广泛的应用仍然是 Java 开发者的重要工具。本文介绍了 Swing 的基础知识,包括创建窗口、添加各种组件、使用布局管理器、事件处理,以及简单的应用实例。

掌握 Swing 可以帮助你创建跨平台的桌面应用程序,无论是简单的工具还是复杂的企业软件,Swing 都能胜任。

练习与延伸学习

练习题

  1. 创建一个带有标签、文本框和按钮的窗口,当用户输入姓名并点击按钮时,显示一个欢迎消息。
  2. 使用不同的布局管理器创建一个表单,包含多个输入字段和提交按钮。
  3. 开发一个简单的图像浏览器,可以打开和显示图像文件。
  4. 创建一个绘图应用,允许用户使用鼠标在画布上绘制简单图形。

进一步学习资源

  • 官方 Java Swing 教程
  • Java Swing 组件详解
  • Swing 高级主题:自定义组件
  • 使用 Swing 创建响应式界面
  • Swing 与数据库交互
警告

虽然 Swing 是跨平台的,但在某些情况下,不同操作系统上的显示可能有细微差别。始终在目标平台上测试您的应用程序。

通过上述内容的学习和实践,你将能够掌握 Java Swing 的基础知识,并为构建更复杂的 GUI 应用程序打下坚实基础。