前置知识: Java

Java Swing 图形界面

10 minIntermediate2026/5/3

Swing 组件体系、事件驱动与 GUI 应用开发。

1. Swing 概述 | Swing Overview

Swing 是 Java 提供的一个 GUI (形用户界面) 工具包,是 AWT (Abstract Window Toolkit) 的增强版本。Swing 提供了丰富的组件和功能,用于创建跨平台的桌面应用程序。

1.1 Swing 的特点

  • 纯 Java 实现:Swing 组件完全由 Java 实现,不依赖于底层操作系统的 GUI 组件
  • 跨平台:相同的 Swing 代码可以在不同的操作系统上运行,保持一致的外观和行为
  • 轻量级组件:Swing 组件不依赖于本地平台的 GUI 组件,而是在 Java 中模拟实现
  • 丰富的组件:提供了大量的 GUI 组件,如按钮、文本框、列表、表格等
  • 可定制性:可以通过 Look and Feel 机制更改应用程序的外观
  • 事件驱动:基于事件处理模型,响应用户的操作

1.2 Swing 与 AWT 的区别

特性AWTSwing
实现方式依赖本地平台 GUI 组件纯 Java 实现
组件重量级组件轻量级组件
外观一致性依赖平台,不同平台外观不同跨平台一致的外观
组件丰富度基础组件丰富的组件库
性能通常更快可能稍慢但更灵活
## 2. Swing 基础组件Basic Components

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

2.1 顶层容器

  • JFrame:主窗口,包含标题栏、最小化/最大化/关闭按钮
  • JDialog:对话框窗口,通常用于显示消息或获取用户输入
  • JApplet:小程序容器,用于在网页中运行 Java 应用

2.2 中间组件

  • JPanel:面板,用于组织和布局其他组件
  • JScrollPane:带滚动条的面板,用于显示超出容器大小的内容
  • JSplitPane:分割面板,用于将容器分为两个可调整大小的部分
  • JTabbedPane:选项卡面板,用于在同一区域显示多个面板

2.3 基本控件

  • JButton:按钮,用于触发操作
  • JTextField:文本输入框,用于输入单行文本
  • JTextArea:文本区域,用于输入多行文本
  • JLabel:标签,用于显示文本或
  • JCheckBox:复选框,用于选择多个选项
  • JRadioButton:单选按钮,用于从多个选项中选择一个
  • JComboBox:下拉列表,用于从预定义选项中选择
  • JList:列表,用于显示多个选项
  • JTable:表格,用于显示二维数据
  • JSlider:滑块,用于在范围内选择值
  • JProgressBar:进度条,用于显示操作进度

3. 布局管理器 | Layout Managers

布局管理器负责组件在容器中的排列方式,Swing 提供了多种布局管理器:

3.1 FlowLayout

  • 特点:组件按照从左到右、从上到下的顺序排列
  • 适用场景:简单的组件排列,如按钮组
  • 示例
 JPanel panel = new JPanel();
 panel.setLayout(new FlowLayout());
 panel.add(new JButton("Button 1"));
 panel.add(new JButton("Button 2"));
 panel.add(new JButton("Button 3"));

3.2 BorderLayout

  • 特点:将容器分为东、西、南、北、中五个区域
  • 适用场景:主窗口布局,如菜单栏在北,状态栏在南,内容在中
  • 示例
 JFrame frame = new JFrame("BorderLayout Example");
 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);

3.3 GridLayout

  • 特点:将容器分为规则的网格,每个单元格大小相同
  • 适用场景:需要整齐排列的组件,如计算器按钮
  • 示例
 JPanel panel = new JPanel();
 panel.setLayout(new GridLayout(3, 3)); // 3行3列
 for (int i = 1; i <= 9; i++) {
  panel.add(new JButton("" + i));
 }

3.4 GridBagLayout

  • 特点:灵活的网格布局,可以指定组件的位置、大小和权重
  • 适用场景:复杂的布局需求
  • 示例
 JPanel panel = new JPanel();
 panel.setLayout(new GridBagLayout());
 GridBagConstraints gbc = new GridBagConstraints();
 // 添加第一个组件
 JButton button1 = new JButton("Button 1");
 gbc.gridx = 0;
 gbc.gridy = 0;
 gbc.gridwidth = 1;
 gbc.gridheight = 1;
 gbc.fill = GridBagConstraints.HORIZONTAL;
 panel.add(button1, gbc);
 // 添加第二个组件
 JButton button2 = new JButton("Button 2");
 gbc.gridx = 1;
 gbc.gridy = 0;
 gbc.gridwidth = 2;
 gbc.fill = GridBagConstraints.HORIZONTAL;
 panel.add(button2, gbc);

3.5 CardLayout

  • 特点:在同一区域显示多个组件,但每次只显示一个
  • 适用场景:选项卡式界面,如向导或多步骤表单
  • 示例
 JPanel panel = new JPanel();
 CardLayout cardLayout = new CardLayout();
 panel.setLayout(cardLayout);
 // 添加卡片
 panel.add(new JButton("Card 1"), "card1");
 panel.add(new JButton("Card 2"), "card2");
 panel.add(new JButton("Card 3"), "card3");
 // 显示特定卡片
 cardLayout.show(panel, "card2");

4. 事件处理 | Event Handling

Swing 使用事件处理模型来响应用户的操作,主要包括以下几个部分:

4.1 事件

  • ActionEvent:按钮点击、菜单项选择等操作
  • MouseEvent:鼠标点击、移动、拖动等操作
  • KeyEvent:键盘按键操作
  • WindowEvent:窗口打开、关闭、最小化等操作
  • FocusEvent:组件获得或失去焦点的操作

4.2 事件监听器

事件监听器是实现了特定接口的对象,用于处理特定型的事件

  • ActionListener:处理 ActionEvent
  • MouseListener:处理 MouseEvent
  • KeyListener:处理 KeyEvent
  • WindowListener:处理 WindowEvent
  • FocusListener:处理 FocusEvent

4.3 事件处理示例

 import javax.swing.*;
 import java.awt.event.*;
 public class EventHandlingExample {
  public static void main(String[] args) {
  JFrame frame = new JFrame("Event Handling Example");
  frame.setSize(300, 200);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  JPanel panel = new JPanel();
  JButton button = new JButton("Click Me");
  // 添加动作监听器
  button.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  JOptionPane.showMessageDialog(frame, "Button clicked!");
  }
  });
  panel.add(button);
  frame.add(panel);
  frame.setVisible(true);
  }
 }

4.4 适配器

为了简化事件监听器的实现,Swing 提供了适配器,这些实现了相应的监听器接口,但所有方法都是空实现:

  • MouseAdapter:实现 MouseListener 接口
  • KeyAdapter:实现 KeyListener 接口
  • WindowAdapter:实现 WindowListener 接口
  • FocusAdapter:实现 FocusListener 接口 使用适配器可以只重写需要的方法,而不是实现所有方法:
 button.addMouseListener(new MouseAdapter() {
  @Override
  public void mouseClicked(MouseEvent e) {
  System.out.println("Mouse clicked!");
  }
 }

5. Swing 高级特性 | Advanced Features

5.1 对话框 | Dialogs

Swing 提供了多种对话框,用于显示消息、获取用户输入等:

  • JOptionPane:显示消息、确认、输入等对话框
  • JFileChooser:文件选择对话框
  • JColorChooser:颜色选择对话框 示例:
 // 显示消息对话框
 JOptionPane.showMessageDialog(frame, "Hello, Swing!");
 // 显示确认对话框
 int option = JOptionPane.showConfirmDialog(frame, "Are you sure?");
 if (option == JOptionPane.YES_OPTION) {
  System.out.println("User clicked Yes");
 }
 // 显示输入对话框
 String input = JOptionPane.showInputDialog(frame, "Enter your name:");
 System.out.println("User entered: " + input);
 // 显示文件选择对话框
 JFileChooser fileChooser = new JFileChooser();
 int result = fileChooser.showOpenDialog(frame);
 if (result == JFileChooser.APPROVE_OPTION) {
  System.out.println("Selected file: " + fileChooser.getSelectedFile());
 }
 // 显示颜色选择对话框
 Color color = JColorChooser.showDialog(frame, "Choose a color", Color.RED);
 System.out.println("Selected color: " + color);

5.2 菜单 | Menus

Swing 提供了完整的菜单系统,包括菜单栏、菜单和菜单项:

 JFrame frame = new JFrame("Menu Example");
 frame.setSize(400, 300);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 // 创建菜单栏
 JMenuBar menuBar = new JMenuBar();
 // 创建文件菜单
 JMenu fileMenu = new JMenu("File");
 JMenuItem newItem = new JMenuItem("New");
 JMenuItem openItem = new JMenuItem("Open");
 JMenuItem saveItem = new JMenuItem("Save");
 JMenuItem exitItem = new JMenuItem("Exit");
 // 添加菜单项到文件菜单
 fileMenu.add(newItem);
 fileMenu.add(openItem);
 fileMenu.add(saveItem);
 fileMenu.addSeparator(); // 添加分隔线
 fileMenu.add(exitItem);
 // 创建编辑菜单
 JMenu editMenu = new JMenu("Edit");
 JMenuItem cutItem = new JMenuItem("Cut");
 JMenuItem copyItem = new JMenuItem("Copy");
 JMenuItem pasteItem = new JMenuItem("Paste");
 // 添加菜单项到编辑菜单
 editMenu.add(cutItem);
 editMenu.add(copyItem);
 editMenu.add(pasteItem);
 // 添加菜单到菜单栏
 menuBar.add(fileMenu);
 menuBar.add(editMenu);
 // 设置菜单栏
 frame.setJMenuBar(menuBar);
 // 添加退出菜单项的监听器
 exitItem.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  System.exit(0);
  }
 }
 frame.setVisible(true);

5.3 表格 | Tables

JTable 组件用于显示和编辑二维数据:

 JFrame frame = new JFrame("Table Example");
 frame.setSize(500, 300);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 // 列名
 String[] columnNames = {"ID", "Name", "Age", "City"};
 // 数据
 Object[][] data = {
  {1, "John", 25, "New York"},
  {2, "Mary", 30, "London"},
  {3, "Bob", 35, "Paris"},
  {4, "Alice", 28, "Tokyo"}
 }
 // 创建表格
 JTable table = new JTable(data, columnNames);
 // 添加滚动条
 JScrollPane scrollPane = new JScrollPane(table);
 frame.add(scrollPane);
 frame.setVisible(true);

5.4 树 | Trees

JTree 组件用于显示层次结构数据:

 JFrame frame = new JFrame("Tree Example");
 frame.setSize(400, 300);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 // 创建根节点
 defaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
 // 创建子节点
 defaultMutableTreeNode node1 = new DefaultMutableTreeNode("Node 1");
 defaultMutableTreeNode node2 = new DefaultMutableTreeNode("Node 2");
 defaultMutableTreeNode node3 = new DefaultMutableTreeNode("Node 3");
 // 添加子节点到根节点
 root.add(node1);
 root.add(node2);
 root.add(node3);
 // 创建子子节点
 defaultMutableTreeNode node1_1 = new DefaultMutableTreeNode("Node 1.1");
 defaultMutableTreeNode node1_2 = new DefaultMutableTreeNode("Node 1.2");
 node1.add(node1_1);
 node1.add(node1_2);
 // 创建树
 JTree tree = new JTree(root);
 // 添加滚动条
 JScrollPane scrollPane = new JScrollPane(tree);
 frame.add(scrollPane);
 frame.setVisible(true);

6. 外观与感觉 | Look and Feel

Swing 允许通过 Look and Feel (L&F) 机制更改应用程序的外观:

6.1 内置的 Look and Feel

  • Metal:默认的跨平台外观
  • Nimbus:现代的跨平台外观
  • Windows:Windows 风格的外观
  • Windows Classic:经典 Windows 风格的外观
  • Motif:Unix/Linux 风格的外观
  • Mac OS X:Mac 风格的外观(仅在 Mac 系统上可用)

6.2 设置 Look and Feel

 import javax.swing.*;
 import javax.swing.plaf.nimbus.NimbusLookAndFeel;
 public class LookAndFeelExample {
  public static void main(String[] args) {
  try {
  // 设置 Nimbus Look and Feel
  UIManager.setLookAndFeel(new NimbusLookAndFeel());
  // 或者使用系统默认的 Look and Feel
  // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
  } catch (Exception e) {
  e.printStackTrace();
  }
  // 创建并显示 GUI
  JFrame frame = new JFrame("Look and Feel Example");
  frame.setSize(300, 200);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  JPanel panel = new JPanel();
  panel.add(new JButton("Button"));
  panel.add(new JTextField(20));
  panel.add(new JCheckBox("Check Box"));
  frame.add(panel);
  frame.setVisible(true);
  }
 }

7. 实战示例 | Practical Examples

7.1 简单的计算器

 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 public class Calculator {
  private JFrame frame;
  private JTextField textField;
  private String operator = "";
  private double firstNumber = 0;
  private boolean start = true;
  public Calculator() {
  frame = new JFrame("Calculator");
  frame.setSize(300, 400);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setLayout(new BorderLayout());
  // 创建文本框
  textField = new JTextField();
  textField.setFont(new Font("Arial", Font.PLAIN, 24));
  textField.setHorizontalAlignment(JTextField.RIGHT);
  frame.add(textField, BorderLayout.NORTH);
  // 创建按钮面板
  JPanel buttonPanel = new JPanel();
  buttonPanel.setLayout(new GridLayout(4, 4, 5, 5));
  // 按钮标签
  String[] buttons = {
  "7", "8", "9", "/",
  "4", "5", "6", "*",
  "1", "2", "3", "-",
  "C", "0", "=", "+"
  };
  // 创建并添加按钮
  for (String button : buttons) {
  JButton btn = new JButton(button);
  btn.setFont(new Font("Arial", Font.PLAIN, 18));
  btn.addActionListener(new ButtonClickListener());
  buttonPanel.add(btn);
  }
  frame.add(buttonPanel, BorderLayout.CENTER);
  frame.setVisible(true);
  }
  private class ButtonClickListener implements ActionListener {
  @Override
  public void actionPerformed(ActionEvent e) {
  String command = e.getActionCommand();
  if (command.charAt(0) >= '0' && command.charAt(0) <= '9' || command.equals(".")) {
  if (start) {
  textField.setText("");
  start = false;
  }
  textField.setText(textField.getText() + command);
  } else if (command.equals("C")) {
  textField.setText("");
  operator = "";
  firstNumber = 0;
  start = true;
  } else if (command.equals("=")) {
  double secondNumber = Double.parseDouble(textField.getText());
  double result = 0;
  switch (operator) {
  case "+":
  result = firstNumber + secondNumber;
  break;
  case "-":
  result = firstNumber - secondNumber;
  break;
  case "*":
  result = firstNumber * secondNumber;
  break;
  case "/":
  result = firstNumber / secondNumber;
  break;
  }
  textField.setText(String.valueOf(result));
  operator = "";
  start = true;
  } else {
  if (!start) {
  firstNumber = Double.parseDouble(textField.getText());
  operator = command;
  start = true;
  }
  }
  }
  }
  public static void main(String[] args) {
  new Calculator();
  }
 }

7.2 简单的文本编辑器

 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.io.*;
 public class TextEditor {
  private JFrame frame;
  private JTextArea textArea;
  private JMenuBar menuBar;
  private JMenu fileMenu;
  private JMenuItem newItem, openItem, saveItem, exitItem;
  private File currentFile = null;
  public TextEditor() {
  frame = new JFrame("Text Editor");
  frame.setSize(600, 400);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  // 创建文本区域
  textArea = new JTextArea();
  textArea.setFont(new Font("Arial", Font.PLAIN, 14));
  JScrollPane scrollPane = new JScrollPane(textArea);
  frame.add(scrollPane, BorderLayout.CENTER);
  // 创建菜单栏
  menuBar = new JMenuBar();
  // 创建文件菜单
  fileMenu = new JMenu("File");
  // 创建菜单项
  newItem = new JMenuItem("New");
  openItem = new JMenuItem("Open");
  saveItem = new JMenuItem("Save");
  exitItem = new JMenuItem("Exit");
  // 添加菜单项到文件菜单
  fileMenu.add(newItem);
  fileMenu.add(openItem);
  fileMenu.add(saveItem);
  fileMenu.addSeparator();
  fileMenu.add(exitItem);
  // 添加文件菜单到菜单栏
  menuBar.add(fileMenu);
  // 设置菜单栏
  frame.setJMenuBar(menuBar);
  // 添加事件监听器
  newItem.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  textArea.setText("");
  currentFile = null;
  frame.setTitle("Text Editor");
  }
  });
  openItem.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  JFileChooser fileChooser = new JFileChooser();
  int result = fileChooser.showOpenDialog(frame);
  if (result == JFileChooser.APPROVE_OPTION) {
  currentFile = fileChooser.getSelectedFile();
  try {
  BufferedReader reader = new BufferedReader(new FileReader(currentFile));
  textArea.read(reader, null);
  reader.close();
  frame.setTitle("Text Editor - " + currentFile.getName());
  } catch (IOException ex) {
  ex.printStackTrace();
  }
  }
  }
  });
  saveItem.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  if (currentFile == null) {
  JFileChooser fileChooser = new JFileChooser();
  int result = fileChooser.showSaveDialog(frame);
  if (result == JFileChooser.APPROVE_OPTION) {
  currentFile = fileChooser.getSelectedFile();
  } else {
  return;
  }
  }
  try {
  BufferedWriter writer = new BufferedWriter(new FileWriter(currentFile));
  textArea.write(writer);
  writer.close();
  frame.setTitle("Text Editor - " + currentFile.getName());
  } catch (IOException ex) {
  ex.printStackTrace();
  }
  }
  });
  exitItem.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
  System.exit(0);
  }
  });
  frame.setVisible(true);
  }
  public static void main(String[] args) {
  new TextEditor();
  }
 }

8. 最佳实践 | Best Practices

8.1 性能优化

  • 使用合适的布局管理器:根据界面需求选择合适的布局管理器
  • 避免过度使用重量级组件:重量级组件可能影响性能
  • 使用 SwingUtilities.invokeLater:确保 GUI 操作在事件分发线程中执行
  • 合理使用组件:只创建必要的组件,避免创建过多组件

8.2 代码组织

  • 使用 MVC 模式:将模型、视和控制器分离
  • 模块化设计:将功能划分为模块,提高代码可维护性
  • 命名规范:使用清晰的命名规范,提高代码可读性
  • 注释:添加适当的注释,说明代码的功能和逻辑

8.3 用户体验

  • 响应式设计:确保界面在不同大小的窗口中都能正常显示
  • 合理的布局:使用合理的布局,使界面美观易用
  • 适当的反馈:对用户操作提供适当的反馈,如进度条、消息框等
  • 快捷键:为常用操作提供快捷键,提高用户操作效率

9. 总结 | Summary

Swing 是 Java 提供的功能强大的 GUI 工具包,通过它可以创建跨平台的桌面应用程序。Swing 提供了丰富的组件和功能,包括各种控件、布局管理器、事件处理机制等。 通过学习 Swing,你可以创建各种型的桌面应用程序,从简单的计算器到复杂的文本编辑器。在实际开发中,应根据具体需求选择合适的组件和布局管理器,并遵循相关的最佳实践,以创建美观、高效、用户友好的应用程序。