Java 图形界面(GUI)完整知识点手册
第一部分:Java GUI 概述
1.1 Java GUI 技术发展史
| 技术 | 年代 | 特点 | 现状 |
|---|---|---|---|
| AWT | JDK 1.0 | 依赖本地操作系统组件,重量级 | 基本废弃,但部分概念保留 |
| Swing | JDK 1.2 | 纯 Java 实现,轻量级,可移植 | 主流,仍在大量使用 |
| JavaFX | JDK 8 引入 | 现代化 GUI,支持 CSS、FXML | JDK 11 起从 JDK 移除,独立维护 |
1.2 本文范围
-
主要讲解 Swing(最常用,面试和企业项目主流)
-
补充 AWT 的基础概念(事件模型)
-
简要介绍 JavaFX
第二部分:AWT 基础
2.1 AWT 核心类
text
java.awt 包
├── Component(所有组件的父类)
│ ├── Button
│ ├── Label
│ ├── TextComponent
│ │ ├── TextField
│ │ └── TextArea
│ ├── Checkbox
│ ├── Choice
│ └── Container(容器)
│ ├── Panel
│ ├── Frame(窗口)
│ └── Dialog
├── LayoutManager(布局管理器)
│ ├── FlowLayout
│ ├── BorderLayout
│ ├── GridLayout
│ └── CardLayout
└── Event(事件)
├── ActionEvent
├── MouseEvent
└── KeyEvent
2.2 AWT 示例
java
import java.awt.*;
import java.awt.event.*;
public class AWTExample {
public static void main(String[] args) {
// 创建窗口
Frame frame = new Frame("AWT 示例");
frame.setSize(300, 200);
frame.setLayout(new FlowLayout());
// 创建按钮
Button btn = new Button("点击我");
// 添加事件监听
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击了");
}
});
frame.add(btn);
frame.setVisible(true);
// 窗口关闭事件(AWT 需要手动处理)
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
第三部分:Swing 核心知识点
3.1 Swing 架构
text
javax.swing 包 ├── JComponent(所有 Swing 组件的父类,继承自 AWT 的 Container) │ ├── JButton(按钮) │ ├── JLabel(标签) │ ├── JTextField(单行文本) │ ├── JTextArea(多行文本) │ ├── JCheckBox(复选框) │ ├── JRadioButton(单选按钮) │ ├── JComboBox(下拉列表) │ ├── JList(列表) │ ├── JTable(表格) │ ├── JTree(树形结构) │ ├── JMenuBar(菜单栏) │ ├── JPanel(面板,容器) │ ├── JScrollPane(滚动面板) │ └── JTabbedPane(选项卡面板) └── JFrame(顶级窗口,继承自 AWT 的 Frame)
3.2 Swing 特点
-
轻量级组件:纯 Java 实现,不依赖本地系统
-
可插拔外观(Pluggable Look and Feel):可以切换不同操作系统风格
-
MVC 架构:Model-View-Controller 设计模式
-
双缓冲技术:减少闪烁,提升绘制性能
第四部分:Swing 核心组件详解
4.1 JFrame(顶级窗口)
基本用法
java
import javax.swing.*;
public class JFrameDemo {
public static void main(String[] args) {
// 1. 创建窗口
JFrame frame = new JFrame("我的第一个 Swing 窗口");
// 2. 设置窗口大小
frame.setSize(400, 300);
// 3. 设置关闭操作(点击 X 时退出程序)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 4. 设置窗口位置居中
frame.setLocationRelativeTo(null);
// 5. 设置布局管理器
frame.setLayout(null); // 绝对布局(不推荐)
// 6. 设置窗口可见(必须最后执行)
frame.setVisible(true);
// 7. 其他设置
frame.setResizable(false); // 禁止调整大小
frame.setAlwaysOnTop(true); // 置顶
}
}
JFrame 常用方法
java
frame.setTitle("标题"); // 设置标题
frame.setSize(800, 600); // 设置宽高(像素)
frame.setLocation(100, 50); // 设置位置(x, y)
frame.setLocationRelativeTo(null); // 居中显示
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭时退出
frame.setResizable(false); // 禁止调整窗口大小
frame.setAlwaysOnTop(true); // 窗口置顶
frame.setIconImage(image); // 设置图标
frame.setVisible(true); // 显示窗口(最后调用)
frame.pack(); // 根据组件自动调整窗口大小
关闭操作常量
java
JFrame.EXIT_ON_CLOSE // 退出程序(最常用) JFrame.DISPOSE_ON_CLOSE // 释放窗口资源,但不退出程序 JFrame.HIDE_ON_CLOSE // 隐藏窗口(默认) JFrame.DO_NOTHING_ON_CLOSE // 什么都不做
4.2 JPanel(面板/容器)
特点
-
作为中间容器,用于组织其他组件
-
可以设置布局管理器
-
可以嵌套使用
代码示例
java
import javax.swing.*;
import java.awt.*;
public class JPanelDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("面板示例");
frame.setSize(500, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
// 创建三个面板
JPanel topPanel = new JPanel();
topPanel.setBackground(Color.BLUE);
topPanel.add(new JLabel("顶部面板"));
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.GREEN);
centerPanel.setLayout(new FlowLayout());
centerPanel.add(new JButton("按钮1"));
centerPanel.add(new JButton("按钮2"));
centerPanel.add(new JButton("按钮3"));
JPanel bottomPanel = new JPanel();
bottomPanel.setBackground(Color.RED);
bottomPanel.add(new JLabel("底部面板"));
// 添加到框架
frame.add(topPanel, BorderLayout.NORTH);
frame.add(centerPanel, BorderLayout.CENTER);
frame.add(bottomPanel, BorderLayout.SOUTH);
frame.setVisible(true);
}
}
4.3 常用组件
JLabel(标签)
java
JLabel label = new JLabel("用户名:");
JLabel label2 = new JLabel("带图标", SwingConstants.CENTER);
label2.setFont(new Font("宋体", Font.BOLD, 20));
label2.setForeground(Color.RED);
JTextField(单行文本框)
java
JTextField textField = new JTextField(); // 默认
JTextField textField2 = new JTextField(20); // 指定列数
JTextField textField3 = new JTextField("默认文字", 15);
textField.setText("设置文本");
String text = textField.getText(); // 获取文本
textField.setEditable(false); // 设为只读
JPasswordField(密码框)
java
JPasswordField pwdField = new JPasswordField(15);
pwdField.setEchoChar('*'); // 设置回显字符
char[] pwd = pwdField.getPassword(); // 获取密码(char数组)
// 注意:不要用 String 存储密码,用 char[] 更安全
JTextArea(多行文本域)
java
JTextArea textArea = new JTextArea(10, 30); // 行数,列数
textArea.setLineWrap(true); // 自动换行
textArea.setWrapStyleWord(true); // 按单词换行
textArea.setText("初始文本");
String content = textArea.getText();
// 放入滚动面板
JScrollPane scrollPane = new JScrollPane(textArea);
JButton(按钮)
java
JButton btn1 = new JButton("确定");
JButton btn2 = new JButton("带图标", new ImageIcon("icon.png"));
btn1.setToolTipText("点击此按钮提交"); // 提示文本
btn1.setEnabled(false); // 禁用按钮
btn1.setMnemonic('O'); // 快捷键 Alt+O
JCheckBox(复选框)
java
JCheckBox check1 = new JCheckBox("Java");
JCheckBox check2 = new JCheckBox("Python", true); // 默认选中
check1.isSelected(); // 判断是否选中
JRadioButton(单选按钮)
java
// 必须放在 ButtonGroup 中才能实现互斥
JRadioButton radio1 = new JRadioButton("男");
JRadioButton radio2 = new JRadioButton("女", true); // 默认选中
ButtonGroup group = new ButtonGroup();
group.add(radio1);
group.add(radio2);
JComboBox(下拉列表)
java
String[] items = {"选项1", "选项2", "选项3"};
JComboBox<String> comboBox = new JComboBox<>(items);
comboBox.addItem("选项4"); // 添加选项
comboBox.removeItem("选项2"); // 移除选项
int index = comboBox.getSelectedIndex(); // 获取选中索引
String item = (String) comboBox.getSelectedItem(); // 获取选中值
JList(列表)
java
String[] data = {"项目A", "项目B", "项目C", "项目D"};
JList<String> list = new JList<>(data);
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
JScrollPane scrollPane = new JScrollPane(list); // 需要滚动面板
// 获取选中值
List<String> selected = list.getSelectedValuesList();
JTable(表格)
java
// 数据:二维数组
String[][] data = {
{"1", "张三", "男", "20"},
{"2", "李四", "女", "22"},
{"3", "王五", "男", "21"}
};
String[] columns = {"编号", "姓名", "性别", "年龄"};
JTable table = new JTable(data, columns);
table.setRowHeight(25); // 设置行高
JScrollPane scrollPane = new JScrollPane(table); // 必须加滚动面板
第五部分:布局管理器(LayoutManager)
5.1 概述
布局管理器负责自动排列容器中的组件,避免硬编码坐标。
5.2 FlowLayout(流式布局)
-
从左到右排列,放不下就换行
-
默认居中对齐
java
JPanel panel = new JPanel(new FlowLayout());
// 或
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10)); // 左对齐,间距10
panel.add(new JButton("按钮1"));
panel.add(new JButton("按钮2"));
panel.add(new JButton("按钮3"));
5.3 BorderLayout(边界布局)
-
分为五个区域:NORTH、SOUTH、WEST、EAST、CENTER
-
JFrame 默认使用 BorderLayout
java
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout(10, 10)); // 水平间距,垂直间距
frame.add(new JButton("北"), BorderLayout.NORTH);
frame.add(new JButton("南"), BorderLayout.SOUTH);
frame.add(new JButton("西"), BorderLayout.WEST);
frame.add(new JButton("东"), BorderLayout.EAST);
frame.add(new JButton("中"), BorderLayout.CENTER);
5.4 GridLayout(网格布局)
-
将容器划分为等大的网格
-
每个组件占一个格子
java
JPanel panel = new JPanel(new GridLayout(3, 2, 5, 5)); // 3行2列,间距5
for (int i = 1; i <= 6; i++) {
panel.add(new JButton("按钮" + i));
}
5.5 CardLayout(卡片布局)
-
多个组件重叠,一次只显示一个
-
常用于选项卡效果
java
JPanel panel = new JPanel();
CardLayout cardLayout = new CardLayout();
panel.setLayout(cardLayout);
panel.add(new JLabel("页面1"), "page1");
panel.add(new JLabel("页面2"), "page2");
panel.add(new JLabel("页面3"), "page3");
// 切换页面
cardLayout.show(panel, "page2");
cardLayout.next(panel);
cardLayout.previous(panel);
5.6 BoxLayout(箱式布局)
-
水平或垂直排列组件
java
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // 垂直排列
panel.add(new JButton("按钮1"));
panel.add(Box.createVerticalStrut(10)); // 添加间距
panel.add(new JButton("按钮2"));
5.7 布局管理器对比表
| 布局 | 特点 | 适用场景 |
|---|---|---|
| FlowLayout | 从左到右,自动换行 | 工具栏、按钮组 |
| BorderLayout | 五区域 | 主窗口布局 |
| GridLayout | 等分网格 | 计算器、表单 |
| CardLayout | 重叠切换 | 选项卡、向导 |
| BoxLayout | 水平/垂直排列 | 表单、面板 |
| GridBagLayout | 最灵活最复杂 | 复杂专业界面 |
第六部分:事件处理(Event Handling)
6.1 事件模型(委托事件模型)
text
事件源(组件) → 触发事件 → 事件对象 → 事件监听器 → 执行处理
6.2 核心接口
-
事件源:发生事件的组件(如 JButton)
-
事件对象:封装事件信息(如 ActionEvent)
-
事件监听器:处理事件的接口(如 ActionListener)
6.3 ActionListener(动作事件)
java
import javax.swing.*;
import java.awt.event.*;
public class ActionListenerDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("事件示例");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton btn = new JButton("点击我");
JLabel label = new JLabel("等待点击...");
// 方式1:匿名内部类(最常用)
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("按钮被点击了!");
System.out.println("点击事件触发");
}
});
// 方式2:Lambda 表达式(JDK 8+)
btn.addActionListener(e -> {
label.setText("Lambda 方式");
});
// 方式3:独立监听器类
btn.addActionListener(new MyActionListener());
frame.add(btn);
frame.add(label);
frame.setVisible(true);
}
}
// 独立监听器类
class MyActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("独立的监听器类");
}
}
6.4 MouseListener(鼠标事件)
java
import javax.swing.*;
import java.awt.event.*;
public class MouseListenerDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("鼠标事件");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(Color.LIGHT_GRAY);
// 鼠标监听
panel.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("鼠标单击:(" + e.getX() + ", " + e.getY() + ")");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("鼠标按下");
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("鼠标释放");
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("鼠标进入");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("鼠标离开");
}
});
// 或使用适配器类(只需要重写需要的方法)
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
System.out.println("左键单击");
} else if (e.getButton() == MouseEvent.BUTTON3) {
System.out.println("右键单击");
}
}
});
frame.add(panel);
frame.setVisible(true);
}
}
6.5 KeyListener(键盘事件)
java
JTextField textField = new JTextField(20);
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
System.out.println("按了回车键");
}
System.out.println("按下的键:" + e.getKeyChar());
}
});
6.6 ItemListener(选项事件 - 复选框/下拉列表)
java
JCheckBox checkBox = new JCheckBox("启用功能");
checkBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("选中");
} else {
System.out.println("取消选中");
}
}
});
// Lambda 方式
checkBox.addItemListener(e -> {
boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
System.out.println("状态:" + selected);
});
6.7 DocumentListener(文本变化事件)
java
JTextField textField = new JTextField(20);
textField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
System.out.println("文本插入:" + textField.getText());
}
@Override
public void removeUpdate(DocumentEvent e) {
System.out.println("文本删除:" + textField.getText());
}
@Override
public void changedUpdate(DocumentEvent e) {
// 属性变化(不常用)
}
});
6.8 事件监听器总结
| 监听器 | 事件类 | 适用组件 |
|---|---|---|
| ActionListener | ActionEvent | JButton、JMenuItem、JTextField |
| MouseListener | MouseEvent | 所有 Component |
| MouseMotionListener | MouseEvent | 所有 Component(拖拽、移动) |
| KeyListener | KeyEvent | 所有 Component |
| ItemListener | ItemEvent | JCheckBox、JRadioButton、JComboBox |
| DocumentListener | DocumentEvent | JTextField、JTextArea |
| WindowListener | WindowEvent | JFrame、JDialog |
| FocusListener | FocusEvent | 所有 Component |
第七部分:完整综合示例(登录界面)
java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LoginDemo extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
private JLabel messageLabel;
public LoginDemo() {
setTitle("用户登录系统");
setSize(400, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
// 创建主面板
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// 标题
JLabel titleLabel = new JLabel("用户登录", SwingConstants.CENTER);
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
titleLabel.setForeground(new Color(0, 102, 204));
// 表单面板
JPanel formPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
// 用户名
gbc.gridx = 0;
gbc.gridy = 0;
formPanel.add(new JLabel("用户名:"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
usernameField = new JTextField(15);
formPanel.add(usernameField, gbc);
// 密码
gbc.gridx = 0;
gbc.gridy = 1;
formPanel.add(new JLabel("密 码:"), gbc);
gbc.gridx = 1;
gbc.gridy = 1;
passwordField = new JPasswordField(15);
passwordField.setEchoChar('●');
formPanel.add(passwordField, gbc);
// 按钮面板
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
JButton loginBtn = new JButton("登录");
JButton resetBtn = new JButton("重置");
JButton exitBtn = new JButton("退出");
// 设置按钮颜色
loginBtn.setBackground(new Color(0, 153, 204));
loginBtn.setForeground(Color.WHITE);
loginBtn.setFocusPainted(false);
buttonPanel.add(loginBtn);
buttonPanel.add(resetBtn);
buttonPanel.add(exitBtn);
// 消息标签
messageLabel = new JLabel("请输入用户名和密码", SwingConstants.CENTER);
messageLabel.setForeground(Color.GRAY);
messageLabel.setFont(new Font("宋体", Font.PLAIN, 12));
// 组装
mainPanel.add(titleLabel, BorderLayout.NORTH);
mainPanel.add(formPanel, BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
add(mainPanel, BorderLayout.CENTER);
add(messageLabel, BorderLayout.SOUTH);
// ============ 事件监听 ============
// 登录按钮
loginBtn.addActionListener(e -> handleLogin());
// 回车键登录
usernameField.addActionListener(e -> handleLogin());
passwordField.addActionListener(e -> handleLogin());
// 重置按钮
resetBtn.addActionListener(e -> {
usernameField.setText("");
passwordField.setText("");
messageLabel.setText("已重置");
messageLabel.setForeground(Color.GRAY);
usernameField.requestFocus();
});
// 退出按钮
exitBtn.addActionListener(e -> System.exit(0));
// 窗口关闭确认
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
int choice = JOptionPane.showConfirmDialog(
LoginDemo.this,
"确定要退出吗?",
"确认退出",
JOptionPane.YES_NO_OPTION
);
if (choice == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
});
setVisible(true);
}
private void handleLogin() {
String username = usernameField.getText().trim();
String password = new String(passwordField.getPassword());
if (username.isEmpty() || password.isEmpty()) {
messageLabel.setForeground(Color.RED);
messageLabel.setText("用户名和密码不能为空!");
return;
}
// 模拟验证
if ("admin".equals(username) && "123456".equals(password)) {
messageLabel.setForeground(new Color(0, 153, 0));
messageLabel.setText("登录成功!欢迎 " + username);
JOptionPane.showMessageDialog(
this,
"登录成功!",
"提示",
JOptionPane.INFORMATION_MESSAGE
);
} else {
messageLabel.setForeground(Color.RED);
messageLabel.setText("用户名或密码错误!");
passwordField.setText("");
passwordField.requestFocus();
}
}
public static void main(String[] args) {
// 设置 Swing 外观为系统风格
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 在事件调度线程中创建 GUI
SwingUtilities.invokeLater(() -> new LoginDemo());
}
}
第八部分:Swing 高级特性
8.1 对话框(JOptionPane)
java
// 消息对话框
JOptionPane.showMessageDialog(parent, "这是一个消息");
JOptionPane.showMessageDialog(parent, "带标题", "标题", JOptionPane.INFORMATION_MESSAGE);
// 确认对话框
int result = JOptionPane.showConfirmDialog(parent, "确认删除吗?");
if (result == JOptionPane.YES_OPTION) {
System.out.println("用户点击了是");
} else if (result == JOptionPane.NO_OPTION) {
System.out.println("用户点击了否");
}
// 输入对话框
String input = JOptionPane.showInputDialog(parent, "请输入姓名:");
if (input != null && !input.isEmpty()) {
System.out.println("输入的姓名:" + input);
}
// 选项对话框
String[] options = {"选项A", "选项B", "选项C"};
int choice = JOptionPane.showOptionDialog(
parent,
"请选择一个选项:",
"选择",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]
);
8.2 菜单(JMenuBar)
java
JMenuBar menuBar = new JMenuBar();
// 文件菜单
JMenu fileMenu = new JMenu("文件");
JMenuItem newItem = new JMenuItem("新建");
JMenuItem openItem = new JMenuItem("打开");
JMenuItem saveItem = new JMenuItem("保存");
JMenuItem exitItem = new JMenuItem("退出");
// 快捷键
newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK));
openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK));
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
// 添加分割线
fileMenu.add(newItem);
fileMenu.add(openItem);
fileMenu.add(saveItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
// 事件监听
exitItem.addActionListener(e -> System.exit(0));
// 编辑菜单
JMenu editMenu = new JMenu("编辑");
editMenu.add(new JMenuItem("剪切"));
editMenu.add(new JMenuItem("复制"));
editMenu.add(new JMenuItem("粘贴"));
// 添加到菜单栏
menuBar.add(fileMenu);
menuBar.add(editMenu);
// 设置到框架
frame.setJMenuBar(menuBar);
8.3 弹出菜单(JPopupMenu)
java
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(new JMenuItem("复制"));
popupMenu.add(new JMenuItem("粘贴"));
popupMenu.addSeparator();
popupMenu.add(new JMenuItem("删除"));
// 鼠标右键弹出
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
popupMenu.show(panel, e.getX(), e.getY());
}
}
});
8.4 选项卡(JTabbedPane)
java
JTabbedPane tabbedPane = new JTabbedPane();
JPanel tab1 = new JPanel();
tab1.add(new JLabel("这是第一个选项卡"));
tab1.setBackground(Color.WHITE);
JPanel tab2 = new JPanel();
tab2.add(new JButton("按钮"));
tab2.setBackground(Color.LIGHT_GRAY);
JPanel tab3 = new JPanel(new GridLayout(2, 2));
tab3.add(new JCheckBox("选项1"));
tab3.add(new JCheckBox("选项2"));
tabbedPane.addTab("基本信息", tab1);
tabbedPane.addTab("操作", tab2);
tabbedPane.addTab("设置", tab3);
frame.add(tabbedPane, BorderLayout.CENTER);
8.5 滚动面板(JScrollPane)
java
// 文本域需要滚动 JTextArea textArea = new JTextArea(10, 30); JScrollPane scrollPane = new JScrollPane(textArea); // 设置滚动策略 scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // 表格需要滚动 JTable table = new JTable(data, columns); JScrollPane tableScroll = new JScrollPane(table);
8.6 外观(Look and Feel)
java
// 系统外观(Windows/Mac/Linux)
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// 跨平台外观(Metal)
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
// Nimbus 外观(JDK 6+)
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
// 所有外观
UIManager.LookAndFeelInfo[] looks = UIManager.getInstalledLookAndFeels();
for (UIManager.LookAndFeelInfo info : looks) {
System.out.println(info.getName() + ": " + info.getClassName());
}
8.7 线程安全(Swing 与多线程)
java
// Swing 组件必须在事件调度线程(EDT)中创建和更新
// 错误方式
new Thread(() -> {
label.setText("新文本"); // ❌ 多线程操作 Swing 不安全
}).start();
// 正确方式1:invokeLater
SwingUtilities.invokeLater(() -> {
label.setText("新文本");
});
// 正确方式2:invokeAndWait(等待执行完成)
try {
SwingUtilities.invokeAndWait(() -> {
label.setText("新文本");
});
} catch (Exception e) {
e.printStackTrace();
}
// 在主方法中创建 GUI
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new LoginDemo());
}
第九部分:JavaFX 简要介绍
9.1 特点
-
现代化 GUI 框架,替代 Swing
-
支持 CSS 样式
-
支持 FXML(声明式 UI)
-
硬件加速渲染
-
内置动画、图表、WebView
9.2 简单示例
java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class JavaFXDemo extends Application {
@Override
public void start(Stage primaryStage) {
Button btn = new Button("点击我");
btn.setOnAction(e -> System.out.println("按钮被点击"));
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 200);
primaryStage.setTitle("JavaFX 示例");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
第十部分:Swing 最佳实践与常见问题
10.1 最佳实践
-
所有 GUI 操作在 EDT 线程中执行:使用
SwingUtilities.invokeLater() -
避免使用绝对布局:使用布局管理器
-
组件创建与显示分离:先创建所有组件,最后
setVisible(true) -
使用
pack()而不是setSize():让窗口自适应 -
大文本用 JTextArea + JScrollPane
-
密码用 JPasswordField,用 char[] 获取
-
长时间操作使用 SwingWorker(后台任务)
10.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 组件不显示 | 未添加到容器或未设置布局 | 检查 add() 和布局管理器 |
| 窗口无法关闭 | 未设置关闭操作 | setDefaultCloseOperation() |
| 界面闪烁 | 未使用双缓冲 | Swing 默认双缓冲,检查是否关闭 |
| 卡顿/无响应 | 在 EDT 执行耗时操作 | 使用 SwingWorker 或新线程 |
| 乱码 | 编码问题 | 设置 -Dfile.encoding=UTF-8 |
10.3 SwingWorker(后台任务)
java
import javax.swing.*;
public class SwingWorkerDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("进度示例");
frame.setSize(300, 150);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
JButton startBtn = new JButton("开始");
JLabel label = new JLabel("准备就绪");
startBtn.addActionListener(e -> {
startBtn.setEnabled(false);
// SwingWorker 执行后台任务
SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i <= 100; i++) {
Thread.sleep(50); // 模拟耗时
publish(i); // 更新进度
}
return null;
}
@Override
protected void process(Integer... chunks) {
int progress = chunks[chunks.length - 1];
progressBar.setValue(progress);
label.setText("进度:" + progress + "%");
}
@Override
protected void done() {
startBtn.setEnabled(true);
label.setText("完成!");
}
};
worker.execute();
});
frame.add(progressBar);
frame.add(startBtn);
frame.add(label);
frame.setVisible(true);
}
}
第十一部分:知识点速查表
| 分类 | 组件/类 | 用途 |
|---|---|---|
| 顶层容器 | JFrame | 主窗口 |
| 中间容器 | JPanel | 组织组件 |
| 基本组件 | JLabel | 显示文本/图标 |
| JButton | 按钮 | |
| JTextField | 单行文本输入 | |
| JTextArea | 多行文本输入 | |
| JPasswordField | 密码输入 | |
| 选择组件 | JCheckBox | 复选框 |
| JRadioButton | 单选按钮 | |
| JComboBox | 下拉列表 | |
| JList | 列表 | |
| 高级组件 | JTable | 表格 |
| JTree | 树形结构 | |
| JTabbedPane | 选项卡 | |
| JScrollPane | 滚动面板 | |
| 布局 | FlowLayout | 流式布局 |
| BorderLayout | 边界布局 | |
| GridLayout | 网格布局 | |
| CardLayout | 卡片布局 | |
| BoxLayout | 箱式布局 | |
| 事件 | ActionListener | 动作事件 |
| MouseListener | 鼠标事件 | |
| KeyListener | 键盘事件 | |
| ItemListener | 选项事件 | |
| 对话框 | JOptionPane | 标准对话框 |
| 菜单 | JMenuBar | 菜单栏 |
| JPopupMenu | 右键菜单 | |
| 线程 | SwingUtilities | EDT 工具类 |
| SwingWorker | 后台任务 |
第十二部分:记忆口诀
text
Swing 组件分三层:顶层容器 JFrame,中间面板 JPanel 基本组件有标签,按钮文本框和密码 选择组件复选框,单选按钮下拉框 表格列表滚动条,选项卡和菜单栏 布局管理器五兄弟:流式边界和网格,卡片箱式最灵活 事件模型三要素:事件源和监听器,事件对象传信息 匿名内部类最常用,Lambda 表达式更简洁 GUI 操作在 EDT,耗时任务用 Worker 创建完毕再显示,setVisible 最后放
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)