第十一章:Swing高级组件 - 让你的桌面应用更出色!
1. Swing高级组件
1.1 引言:开启高级组件之旅
你好,未来的Java桌面应用大师!在上一章,我们已经认识了Swing的基础组件,像是按钮、文本框这些“小积木”。现在,我们要更进一步,探索Swing中那些更强大、更酷的“高级积木”!它们能让你的应用程序看起来更专业,用起来更方便。准备好了吗?让我们一起揭开Swing高级组件的神秘面纱吧!
1.2 什么是Swing高级组件?
简单来说,Swing高级组件就是那些能帮你处理更复杂数据显示和交互的“瑞士军刀”。想象一下,如果基础组件是砖头,那么高级组件就是预制好的窗户、门或者整个房间模块,能让你的“房子”(应用程序)功能更丰富,结构更清晰。
常见的Swing高级组件有:
- JTable (表格): 用来展示和编辑像Excel表格一样的数据。
- JTree (树): 用来显示层级关系的数据,比如电脑里的文件夹结构。
- JList (列表): 展示一列项目,让用户可以从中选择,比如歌曲列表。
- JTabbedPane (选项卡面板): 像浏览器标签页一样,把不同的功能区隔开,让界面井井有条。
1.3 生活中的例子:高级组件无处不在
为了让你更好地理解,我们来看看这些高级组件在生活中的应用:
-
JTable (表格):
- 场景: 学校的成绩单。每一行是一个学生,每一列是科目名称,单元格里是对应的分数。
- 对应:
JTable
可以完美展示这种行列结构的数据。
-
JTree (树):
- 场景: 你电脑上的文件管理器。C盘下有文件夹,文件夹里又有子文件夹或文件,一层一层展开。
- 对应:
JTree
最擅长表现这种树状的层级结构。
-
JList (列表):
- 场景: 音乐播放器里的歌曲列表,或者购物App里的商品分类列表。
- 对应:
JList
可以清晰地列出一系列选项供用户查看和选择。
-
JTabbedPane (选项卡面板):
- 场景: 你的网络浏览器。你可以同时打开好几个网页,每个网页在一个标签页里,点击标签就能切换。
- 对应:
JTabbedPane
就是帮你实现这种多标签页切换功能的利器。
1.4 核心组件详解:深入了解它们的“内心”
1.4.1 JTable:数据展示的得力助手
JTable
是一个非常强大的组件,用于以表格形式显示数据。你可以自定义表头、单元格内容,甚至允许用户直接在表格里编辑数据。
- 如何创建? 通常需要一个数据模型(
TableModel
)来告诉JTable
要显示什么数据,以及列名是什么。 - 常用操作: 添加行、删除行、获取选中单元格的数据等。
1.4.2 JTree:层级数据的完美呈现
JTree
用于显示具有层级关系的数据。每个项目称为一个“节点”(TreeNode
),节点可以有子节点。
- 如何创建? 需要一个根节点,然后逐级添加子节点。
- 常用操作:展开/折叠节点、获取选中节点、动态添加/删除节点。
1.4.3 JList:简单直观的选项列表
JList
用于显示一个项目列表,用户可以从中选择一项或多项。
- 如何创建? 可以直接用一个数组或
Vector
对象来初始化列表中的数据。 - 常用操作: 获取选中项、设置单选/多选模式。
1.4.4 JTabbedPane:界面管理的魔术师
JTabbedPane
允许你在同一个窗口区域内放置多个面板(通常是JPanel
),并通过点击标签来切换显示哪个面板。
- 如何创建? 创建一个
JTabbedPane
对象,然后使用addTab()
方法添加标签页和对应的组件。 - 常用操作: 添加标签页、移除标签页、获取当前选中的标签页。
1.5 动手写代码:打造一个迷你信息中心!
理论说再多,不如动手敲一遍!下面这个例子会把我们刚才学到的高级组件都用上,创建一个简单的“学生信息中心”:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
public class AdvancedSwingDemoEnhanced {
public static void main(String[] args) {
// SwingUtilities.invokeLater确保GUI更新在事件调度线程中执行,这是Swing编程的最佳实践
SwingUtilities.invokeLater(() -> {
// 创建我们自定义的GUI
createAndShowGUI();
});
}
private static void createAndShowGUI() {
// 1. 创建主窗口 (JFrame)
JFrame frame = new JFrame("学生信息中心 - Swing高级组件演示");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 点关闭按钮时退出程序
frame.setSize(700, 500); // 设置窗口大小
// 2. 创建选项卡面板 (JTabbedPane)
JTabbedPane tabbedPane = new JTabbedPane();
// --- 面板1: 学生成绩表格 (JTable) ---
JPanel tablePanel = new JPanel(new BorderLayout()); // 使用BorderLayout布局
String[] columnNames = {"学号", "姓名", "科目", "成绩"};
Object[][] studentData = {
{"S001", "小明", "数学", 95},
{"S002", "小红", "语文", 88},
{"S003", "小刚", "英语", 92},
{"S001", "小明", "物理", 85}
};
// DefaultTableModel是TableModel的一个简单实现
DefaultTableModel tableModel = new DefaultTableModel(studentData, columnNames);
JTable studentTable = new JTable(tableModel);
// JScrollPane用于当表格内容过多时提供滚动条
JScrollPane tableScrollPane = new JScrollPane(studentTable);
tablePanel.add(new JLabel("学生成绩表:", JLabel.CENTER), BorderLayout.NORTH);
tablePanel.add(tableScrollPane, BorderLayout.CENTER);
tabbedPane.addTab("成绩查询", null, tablePanel, "点击查看学生成绩");
// --- 面板2: 班级与学生结构 (JTree) ---
JPanel treePanel = new JPanel(new BorderLayout());
// 创建树的根节点
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("学校");
// 创建一级节点:班级
DefaultMutableTreeNode grade10 = new DefaultMutableTreeNode("高一年级");
DefaultMutableTreeNode class1 = new DefaultMutableTreeNode("一班");
class1.add(new DefaultMutableTreeNode("小明"));
class1.add(new DefaultMutableTreeNode("小华"));
DefaultMutableTreeNode class2 = new DefaultMutableTreeNode("二班");
class2.add(new DefaultMutableTreeNode("小红"));
grade10.add(class1);
grade10.add(class2);
DefaultMutableTreeNode grade11 = new DefaultMutableTreeNode("高二年级");
DefaultMutableTreeNode class3 = new DefaultMutableTreeNode("三班");
class3.add(new DefaultMutableTreeNode("小刚"));
grade11.add(class3);
rootNode.add(grade10);
rootNode.add(grade11);
// 用根节点创建JTree
JTree classTree = new JTree(rootNode);
JScrollPane treeScrollPane = new JScrollPane(classTree);
treePanel.add(new JLabel("班级学生结构图:", JLabel.CENTER), BorderLayout.NORTH);
treePanel.add(treeScrollPane, BorderLayout.CENTER);
tabbedPane.addTab("班级结构", null, treePanel, "查看班级和学生分布");
// --- 面板3: 兴趣小组列表 (JList) ---
JPanel listPanel = new JPanel(new BorderLayout());
String[] interestGroups = {"⚽ 足球社", "🏀 篮球社", "🎨 美术社", "💻 编程俱乐部", "🎤 合唱团", "♟️ 棋艺社"};
JList<String> groupList = new JList<>(interestGroups);
groupList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // 设置为单选模式
JScrollPane listScrollPane = new JScrollPane(groupList);
listPanel.add(new JLabel("可选兴趣小组:", JLabel.CENTER), BorderLayout.NORTH);
listPanel.add(listScrollPane, BorderLayout.CENTER);
tabbedPane.addTab("兴趣小组", null, listPanel, "选择你感兴趣的小组");
// 3. 将选项卡面板添加到主窗口
frame.add(tabbedPane);
// 4. 让窗口居中显示并可见
frame.setLocationRelativeTo(null); // 窗口居中
frame.setVisible(true); // 显示窗口
}
}
代码解释加油站:
SwingUtilities.invokeLater
: 这是Swing中处理GUI更新的标准方式,确保所有GUI操作都在事件分发线程(EDT)中执行,避免线程安全问题。JFrame
: 我们的老朋友,应用程序的主窗口。JTabbedPane
: 创建了一个选项卡容器。JPanel
: 我们为每个标签页内容创建了一个JPanel
作为容器,并使用了BorderLayout
来简单布局标题和主要组件。JTable
和DefaultTableModel
:DefaultTableModel
帮助我们轻松定义表格的列名和数据。然后用这个模型创建JTable
。JScrollPane
: 当表格、树或列表的内容超出了显示区域时,JScrollPane
会自动提供滚动条,非常实用!DefaultMutableTreeNode
: 这是创建JTree
节点时常用的类,可以方便地添加子节点。JList
: 直接用一个字符串数组初始化了列表项。setSelectionMode
可以设置列表是单选还是多选。tabbedPane.addTab()
: 这个方法有多个重载版本,我们用了addTab(String title, Icon icon, Component component, String tip)
,可以设置标题、图标(我们这里是null)、要显示的组件以及鼠标悬停时的提示文本。frame.setLocationRelativeTo(null)
: 一个让窗口在屏幕上居中显示的小技巧。
1.6 知识点回顾
- JTable: 表格数据的展示与编辑,核心是
TableModel
。 - JTree: 层级数据的展示,核心是
TreeNode
。 - JList: 列表数据的展示与选择。
- JTabbedPane: 多面板的选项卡式管理,让界面更有条理。
- JScrollPane: 为内容可能超限的组件提供滚动功能。
- SwingUtilities.invokeLater: GUI操作的“安全通道”。
掌握了这些高级组件,你就拥有了构建复杂、交互性强的桌面应用的强大武器!
1.7 下一步:继续探索!
Swing的世界远不止这些!接下来,你可以尝试:
- 学习更复杂的
TableModel
,例如从数据库动态加载数据到JTable
。 - 研究
JTree
的自定义节点渲染和事件处理。 - 探索
JList
的自定义单元格渲染。 - 了解Swing中的布局管理器,它们能帮你更灵活地安排组件位置。
- 尝试给你的应用添加菜单栏(
JMenuBar
)、工具栏(JToolBar
)等。
继续努力,你一定能成为Swing应用开发的高手!祝你编程愉快!
2. Swing布局管理 - 让你的应用界面“活”起来!
2.1 引言:给组件安个合适的“家”
你好,未来的界面设计小能手!在之前的章节中,我们学会了如何创建各种Swing组件,比如按钮、文本框等等。但是,光有组件还不够,我们还需要告诉Java如何把这些组件摆放到窗口中,让它们看起来整齐美观,用起来顺手。这就是“布局管理”要干的活儿!想象一下,你在整理房间,书要放书架,衣服要放衣柜,所有东西各就其位,房间才显得井井有条。Swing的布局管理器就是帮你整理“组件房间”的得力助手!
2.2 什么是Swing布局管理器?
简单来说,Swing布局管理器就是一套规则,它决定了容器(比如JFrame
窗口或者JPanel
面板)中的组件如何排列、如何占据空间、以及当窗口大小改变时如何调整自己。
如果没有布局管理器,你就得手动计算每个组件的精确坐标(x, y)和大小(width, height),这不仅繁琐,而且当窗口大小变化或者在不同屏幕分辨率的电脑上运行时,界面很可能就乱作一团了。布局管理器能帮我们自动处理这些麻烦事,让界面更具适应性和美观性。
2.3 生活中的例子:布局无处不在
为了让你更好地理解不同的布局管理器,我们来看看生活中的一些场景:
-
FlowLayout (流式布局):
- 场景: 想象你在写一篇文章,文字从左到右排列,一行写满了就自动换到下一行。或者,你在超市排队结账,大家一个接一个地排成一队。
- 对应:
FlowLayout
就是这样,它会按照组件添加的顺序,从左到右(默认)或从右到左地排列组件,一行放不下就自动换行。
-
BorderLayout (边界布局):
- 场景: 想象一个房间的布局。房间有上(北)、下(南)、左(西)、右(东)四面墙,以及中间的主要活动区域。
- 对应:
BorderLayout
把容器分成五个区域:NORTH
(北),SOUTH
(南),WEST
(西),EAST
(东), 和CENTER
(中)。你可以把组件分别放到这五个区域里。通常中间区域会占据剩余的所有空间。
-
GridLayout (网格布局):
- 场景: 看看你家的棋盘(比如象棋或围棋),或者日历的月份视图。它们都是由一个个大小相同的格子组成的。
- 对应:
GridLayout
会把容器分割成指定行数和列数的网格,所有组件会被平均分配到这些格子里,并且每个格子大小都一样。
-
BoxLayout (盒式布局):
- 场景: 想象一堆叠起来的书(垂直排列),或者一排并列停放的自行车(水平排列)。
- 对应:
BoxLayout
允许你将组件沿着单个轴线(水平或垂直)排列。组件可以有不同的大小,并且你可以指定对齐方式。
-
CardLayout (卡片布局):
- 场景: 想象一副扑克牌,你一次只能看到最上面的一张牌,但你可以切换看不同的牌。或者像某些软件安装向导,一步一步显示不同的设置界面。
- 对应:
CardLayout
允许你在同一个空间显示多个组件(卡片),但一次只显示其中一个。你可以通过编程来切换显示哪张“卡片”。
-
GridBagLayout (网格包布局):
- 场景: 想象一个非常灵活的模块化书架,你可以放置不同大小的书籍、装饰品,并且可以精确控制它们在书架上的位置和占据的空间,甚至可以让一个物品跨越多行或多列。
- 对应:
GridBagLayout
是最强大也最复杂的布局管理器。它将容器划分为一个灵活的网格,你可以精确控制每个组件在网格中的位置、大小、以及如何填充空间,非常适合构建复杂的GUI界面。
2.4 核心布局管理器详解:深入它们的“工作原理”
2.4.1 FlowLayout:简单随和的排列者
FlowLayout
是最简单的布局管理器,它像水流一样安排组件。
- 特点: 默认从左到右排列,一行排满后自动换到下一行。可以设置对齐方式(居左、居中、居右)和组件间的水平、垂直间距。
- 适用场景: 简单地排列少量按钮、标签等,比如对话框底部的“确定”、“取消”按钮。
2.4.2 BorderLayout:区域分明的规划师
BorderLayout
将容器划分为五个逻辑区域。
- 特点:
NORTH
和SOUTH
组件在高度上采用其首选高度,宽度上填满容器;WEST
和EAST
组件在宽度上采用其首选宽度,高度上填满NORTH
和SOUTH
之间的剩余空间;CENTER
组件填满所有剩余空间。 - 适用场景: 典型的窗口布局,如顶部菜单栏/工具栏 (
NORTH
),底部状态栏 (SOUTH
),左侧导航栏 (WEST
),右侧信息面板 (EAST
),中间主要工作区 (CENTER
)。
2.4.3 GridLayout:整齐划一的分割者
GridLayout
将容器划分为大小相等的网格单元。
- 特点: 所有单元格大小相同,组件会拉伸以填满其所在的单元格。你需要指定行数和列数。
- 适用场景: 计算器按钮、棋盘游戏界面等需要组件大小一致且排列整齐的场景。
2.4.4 BoxLayout:单向排列的组织者
BoxLayout
允许组件沿水平(BoxLayout.X_AXIS
)或垂直(BoxLayout.Y_AXIS
)方向排列。
- 特点: 组件可以有不同的大小。可以插入“胶水”(
Box.createGlue()
)或“支柱”(Box.createHorizontalStrut()
/Box.createVerticalStrut()
)来控制间距和对齐。 - 适用场景: 工具栏、菜单项列表、垂直排列的表单项等。
2.4.5 CardLayout:空间复用的魔术师
CardLayout
像一叠卡片一样管理组件,一次只显示一个。
- 特点: 每个组件被视为一张“卡片”。你需要通过名称来引用和切换卡片。
- 适用场景: 选项卡面板(虽然
JTabbedPane
更常用)、安装向导、多步骤表单等需要在同一区域显示不同内容的场景。
2.4.6 GridBagLayout:精细控制的大师(简介)
GridBagLayout
是最灵活但也最复杂的布局管理器。
- 特点: 通过
GridBagConstraints
对象来精确控制每个组件的放置位置(gridx
,gridy
)、跨越的行数和列数(gridwidth
,gridheight
)、填充方式(fill
)、对齐方式(anchor
)以及权重(weightx
,weighty
,用于控制窗口缩放时组件如何分配额外空间)。 - 适用场景: 几乎任何复杂的界面布局都可以用它实现,但学习曲线较陡峭。
2.5 动手写代码:打造一个“我的工具箱”应用!
理论学习后,我们来动手实践一下,用多种布局管理器组合出一个简单的“我的工具箱”界面。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyToolboxApp {
private static JPanel cardPanel; // 用于CardLayout的面板
private static CardLayout cardLayout; // CardLayout管理器
private static JLabel statusLabel; // 状态标签
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGUI();
});
}
private static void createAndShowGUI() {
// 1. 创建主窗口 (JFrame)
JFrame frame = new JFrame("我的工具箱 - 布局管理演示");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
// 主窗口使用BorderLayout
frame.setLayout(new BorderLayout(5, 5)); // 水平和垂直间距为5像素
// 2. 创建顶部菜单区 (JPanel + FlowLayout)
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
topPanel.setBorder(BorderFactory.createEtchedBorder()); // 加个边框
topPanel.add(new JButton("文件(F)"));
topPanel.add(new JButton("编辑(E)"));
topPanel.add(new JButton("帮助(H)"));
frame.add(topPanel, BorderLayout.NORTH);
// 3. 创建左侧工具选择区 (JPanel + BoxLayout)
JPanel westPanel = new JPanel();
// 垂直排列的BoxLayout
westPanel.setLayout(new BoxLayout(westPanel, BoxLayout.Y_AXIS));
westPanel.setBorder(BorderFactory.createTitledBorder("选择工具")); // 带标题的边框
JButton calcButton = new JButton("简易计算器");
JButton notepadButton = new JButton("迷你记事本");
JButton colorPickerButton = new JButton("颜色选择器");
// 给按钮添加动作监听,用于切换卡片和更新状态栏
ActionListener toolButtonListener = e -> {
String command = e.getActionCommand();
cardLayout.show(cardPanel, command); // 根据按钮文字切换卡片
statusLabel.setText("当前工具: " + command);
};
calcButton.addActionListener(toolButtonListener);
notepadButton.addActionListener(toolButtonListener);
colorPickerButton.addActionListener(toolButtonListener);
// 设置按钮最大尺寸,使其宽度一致
Dimension buttonSize = new Dimension(150, 30);
calcButton.setMaximumSize(buttonSize);
notepadButton.setMaximumSize(buttonSize);
colorPickerButton.setMaximumSize(buttonSize);
westPanel.add(calcButton);
westPanel.add(Box.createVerticalStrut(10)); // 垂直间距10像素
westPanel.add(notepadButton);
westPanel.add(Box.createVerticalStrut(10));
westPanel.add(colorPickerButton);
westPanel.add(Box.createVerticalGlue()); // 使得按钮靠上对齐
frame.add(westPanel, BorderLayout.WEST);
// 4. 创建中央内容区 (JPanel + CardLayout)
cardLayout = new CardLayout();
cardPanel = new JPanel(cardLayout);
cardPanel.setBorder(BorderFactory.createLoweredBevelBorder());
// 为每个工具创建简单的占位面板
JPanel calculatorPanel = new JPanel();
calculatorPanel.add(new JLabel("这里是简易计算器界面..."));
JPanel notepadPanel = new JPanel();
notepadPanel.add(new JTextArea("迷你记事本内容区...", 5, 20));
JPanel colorPickerPanel = new JPanel();
colorPickerPanel.add(new JLabel("颜色选择器功能区..."));
// 将面板作为卡片添加到CardLayout
// 注意:卡片名称与按钮的ActionCommand一致
cardPanel.add(calculatorPanel, "简易计算器");
cardPanel.add(notepadPanel, "迷你记事本");
cardPanel.add(colorPickerPanel, "颜色选择器");
frame.add(cardPanel, BorderLayout.CENTER);
// 5. 创建底部状态栏 (JPanel + FlowLayout)
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
statusLabel = new JLabel("欢迎使用我的工具箱!");
bottomPanel.add(statusLabel);
bottomPanel.setBorder(BorderFactory.createEtchedBorder());
frame.add(bottomPanel, BorderLayout.SOUTH);
// 6. 让窗口居中显示并可见
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
代码解释加油站:
frame.setLayout(new BorderLayout(5, 5));
: 为主窗口设置BorderLayout
,并指定组件间的水平和垂直间距为5像素。topPanel
: 使用FlowLayout
靠左排列“菜单”按钮。westPanel
: 使用BoxLayout
并设置为BoxLayout.Y_AXIS
,使得工具按钮垂直排列。BorderFactory.createTitledBorder("选择工具")
: 给面板添加一个带标题的边框,更美观。calcButton.setMaximumSize(buttonSize)
:BoxLayout
会考虑组件的最大、最小、首选尺寸。这里设置最大尺寸是为了让所有按钮宽度一致。Box.createVerticalStrut(10)
: 在按钮之间创建固定的垂直间距。Box.createVerticalGlue()
: 添加一个“胶水”组件,它会占据所有可用的额外垂直空间,从而将上面的按钮推向顶部对齐。
cardLayout = new CardLayout(); cardPanel = new JPanel(cardLayout);
: 创建CardLayout
管理器和使用它的面板cardPanel
。cardPanel.add(calculatorPanel, "简易计算器");
: 将一个面板(比如calculatorPanel
)作为一张卡片添加到cardPanel
中,并给这张卡片命名为“简易计算器”。这个名字很重要,之后切换卡片时会用到。ActionListener toolButtonListener
: 创建一个通用的事件监听器。当工具按钮被点击时:e.getActionCommand()
: 获取按钮上显示的文本(我们用它作为卡片名)。cardLayout.show(cardPanel, command);
:CardLayout
的核心方法,用于显示指定名称的卡片。statusLabel.setText(...)
: 更新底部状态栏的文本。
bottomPanel
: 使用FlowLayout
靠左显示状态信息。frame.setLocationRelativeTo(null);
: 窗口居中显示。
2.6 知识点回顾
- 布局管理器的重要性: 自动处理组件的排列、大小和窗口缩放时的适应性。
- FlowLayout: 按顺序流动排列,简单方便。
- BorderLayout: 五区域划分,适合整体窗口布局。
- GridLayout: 等大小网格,适合按钮阵列等。
- BoxLayout: 单向(水平或垂直)排列,灵活控制间距和对齐。
- CardLayout: 空间复用,一次显示一张“卡片”,通过名称切换。
- GridBagLayout (简介): 最强大灵活,但配置复杂,用于精细布局。
- JPanel的嵌套: 可以将不同的
JPanel
(各自使用不同的布局管理器)组合起来,构建复杂的界面结构。 Box
类的辅助:createHorizontalStrut
,createVerticalStrut
,createGlue
等方法可以帮助BoxLayout
更好地控制间距和对齐。
掌握了这些布局管理器,你就拥有了设计美观、实用、且能适应不同环境的Java桌面应用界面的关键技能!
2.7 下一步:继续探索!
布局管理是GUI开发中的一个大学问,今天我们只是打开了一扇门:
- 深入
GridBagLayout
: 如果你需要非常精细和复杂的布局,花时间学习GridBagLayout
和它的GridBagConstraints
是非常值得的。 GroupLayout
: 这是另一种强大的布局管理器(在NetBeans等IDE中常用),它更侧重于组件间的相对关系和对齐。- 自定义布局管理器: 虽然不常用,但你甚至可以创建自己的布局管理器来实现特定的布局逻辑。
- GUI设计工具: 许多IDE(如IntelliJ IDEA, Eclipse, NetBeans)都提供了可视化的GUI设计器,它们可以帮助你通过拖拽组件来布局界面,并自动生成布局代码。这可以大大提高开发效率,尤其是在处理复杂布局时。
- 响应式设计思想: 思考当窗口大小变化时,你的界面元素应该如何响应。哪些组件应该拉伸?哪些应该保持固定大小?哪些应该隐藏或显示?
不断练习,尝试用不同的布局管理器组合出你想要的界面效果。祝你在Java Swing的界面设计之路上越走越远,创造出令人惊艳的应用程序!