背景

首先本文是一个系列的文章,起名为《Java Swing GUi从小白到大神》,主要介绍Java Swing相关概念和实践应用。目前JavaSwingGUI很少作为界面的开发框架,但是对于新手快速掌握Java体系,了解面向对象理念很有必要,同时也能让你了解软件前后端的沟通,本篇是系列博文的第一篇,我们开始吧。

文章概览

  1. JavaSwingGUI基础内容
  2. 如何使用标签和按钮组件
  3. 如何使用布局管理器组件

1. JavaSwingGUI基础内容

1. 组件的层次关系

先从整体上了解组件关系,知道大概有哪些组件,从最顶层组件到最低层的组件。

graph TB
    A(java.awt.Component) --> B(java.awt.Container)
    B(java.awt.Container) --> C(javax.swing.JComponent)
    B(java.awt.Container) --> D(java.awt.Window)
    C(javax.swing.JComponent) --> E(中间容器组件)
    C(javax.swing.JComponent) --> F(基本组件)
    D(java.awt.Window) --> G(独立显示组件)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
└── 中间容器组件
    ├── JPanel
    ├── JScrollPane
    ├── JSplitPane
    ├── JTabbedPane
    ├── JToolBar
    ├── JLayeredPane
    ├── JDesktopPane
    ├── JTable
    ├── JTree
    └── JInternalFrame
    
└── 基本组件
    ├── JButton
    ├── JCheckBox
    ├── JRadioButton
    ├── JTextField
    ├── JTable
    ├── JTree
    ├── JComboBox
    └── JProgressBar

└── 独立显示组件
    ├── JFrame
    ├── JDialog
    ├── JApplet
    └── JWindow

2. 中间容器组件介绍

组件名称 作用
JPanel 称为面板,最常用的中间容器,通常与布局管理器配合使用
JScrollPane 称为滚动面板,包装大内容的组件,支持内容的滚动显示,例如表格、列表或文本区域
JSplitPane 称为分割面板,用于将界面分为两个区域,可调整大小
JTabbedPane 称为卡片面板,用于在同一区域切换多个选项卡
JToolBar 称为工具栏,用于添加按钮,作为快捷按钮
JLayeredPane 称为层叠面板,用于管理组件的 Z 轴顺序(层次)
JDesktopPane 称为虚拟桌面容器,用于管理内部窗口(JInternalFrame)
JInternalFrame 称为内部窗口,通常嵌套在 JDesktopPane 中

中间容器组件的特性,可以添加多个组件,并且可以设置布局管理器,以实现组件的布局和显示。

3. 基本组件介绍

  • 按钮类:
    • JButton:普通按钮。
    • JCheckBox:复选框按钮。
    • JRadioButton:单选按钮。
    • JToggleButton:可切换的按钮。
  • 文本类:
    • JLabel:文本标签,用于显示静态文本或图标。
    • JTextField:单行文本输入框。
    • JPasswordField:密码输入框。
    • JTextArea:多行文本区域。
    • JEditorPane:支持 HTML 和 RTF 的编辑器。
    • JTextPane:支持富文本的多功能文本组件。
  • 菜单类:
    • JMenuBar:菜单栏。
    • JMenu:菜单。
    • JMenuItem:菜单项。
    • JCheckBoxMenuItem:带复选框的菜单项。
    • JRadioButtonMenuItem:带单选按钮的菜单项。
  • 选择类:
    • JComboBox:下拉列表框。
    • JList:列表。
    • JSpinner:数值选择器。
  • 表格和树:
    • JTable:表格,用于显示二维数据。
    • JTree:树,用于显示分层数据。
  • 进度条和滑块:
    • JProgressBar:进度条。
    • JSlider:滑块。
  • 对话框类:
    • JOptionPane:标准对话框。
  • 其他组件:
    • JSeparator:分隔符,用于在菜单或工具栏中分隔组件。
    • JToolTip:工具提示。
    • JViewport:视口,通常与 JScrollPane 配合使用。

4. 独立显示组件介绍

  • JFrame:窗口容器,通常用作主程序窗口。

  • JDialog:对话框容器,用于显示模态或非模态对话框。

  • JApplet:嵌入在浏览器中的小程序(已过时)。

  • JWindow:没有标题栏和边框的窗口。

  • 特点:

    • 直接继承自 java.awt.Container(间接继承 Component)。
    • 每个顶级组件都有一个 JRootPane 作为其内容容器。
    • 不可以直接向顶级组件添加普通组件,需要通过 Content Pane 添加。
    • 每个顶层容器包含一个 JRootPane,它是顶层容器的根容器
    1
    2
    3
    4
    5
    6
    7
    
    JRootPane
      ├── Glass Pane
      ├── Layered Pane
      │   ├── JMenuBar
      │   └── Content Pane
      │       └── User Components
      └── (Optionally) Border and Decorations
    

5. JComponent类介绍

JComponent 类是所有轻量级组件的父类,中间件组件和基础组件都继承它,JComponent类有如下九大特性。

graph LR
    subgraph left[":::yellow 下侧框 ::"]
        direction TB
        left_content["- 为残疾无障碍支持<br>- 指搓支持<br>- 双缓冲支持组件频繁改变<br>- 键绑定让按键似图标"]
    end

    subgraph right[":::yellow 上侧框 ::"]
        direction TB
        right_content["- Tool tips 提示功能<br>- 绘画边框功能<br>- 定制桌面功能<br>- 自定义属性<br>- 对布局功能的支持"]
    end

    center["JComponent 类功能特性"]

    center --> left_content
    center --> right_content

2. 如何使用标签和按钮组件

按钮与标签是常用的基本组件,需要熟练掌握,下面是一个简单的示例。

按钮与标签示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class LableAndButton {
    static final int WIDTH = 300;
    static final int hEIGHT = 200;

    public static void main(String[] args) {
        // 创建窗口
        JFrame frame = new JFrame("Swing 标签与按钮示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLayout(new BorderLayout());

        // 创建标签并设置边框
        JLabel label = new JLabel("这是一个标签");
        // 设置标签边框
        Border labelBorder = BorderFactory.createLineBorder(Color.BLUE, 2); // 蓝色边框,2px
        label.setBorder(BorderFactory.createCompoundBorder(labelBorder, new EmptyBorder(10, 10, 10, 10))); // 设置内边距

        // 创建按钮并设置边框
        JButton button = new JButton("这是一个按钮");
        // 设置按钮边框
        Border buttonBorder = BorderFactory.createLineBorder(Color.RED, 2); // 红色边框,2px
        button.setBorder(BorderFactory.createCompoundBorder(buttonBorder, new EmptyBorder(10, 10, 10, 10))); // 设置内边距

        // 在窗口的不同位置添加组件,设置上下左右距离
        frame.add(label, BorderLayout.NORTH); // 将标签放置在顶部
        frame.add(button, BorderLayout.SOUTH); // 将按钮放置在底部

        // 设置窗口可见
        frame.setVisible(true);
    }
}

3. 如何使用布局管理器组件

布局管理器是在 内容面板 上布局的,基本组件放入内容面板时,根据内容面板提前设置好的布局摆放,其实就是组件的摆放方式就叫 布局管理器 ,大概 9 种摆放方式,逐一了解下。

1. BorderLayout布局管理器

BorderLayout 布局管理器翻译为 边界布局 布局管理器,特点是将内容面板分为 上下左右中 五个区域,分别对应 North、South、East、West、Center

BorderLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class BorderLayoutExample {
    static final int WIDTH = 800;
    static final int HEIGHT = 600;

    public static void main(String[] args) {
        JFrame frame = new JFrame("BorderLayout测试程序");
        frame.setSize(WIDTH, HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建主面板
        JPanel panel = new JPanel();
        frame.setContentPane(panel);
        panel.setLayout(new BorderLayout());

        // 创建按钮
        JButton button1 = new JButton("港币");
        JButton button2 = new JButton("人民币");
        JButton button3 = new JButton("英镑");
        JButton button4 = new JButton("欧元");
        JButton button5 = new JButton("美元");
        JButton button6 = new JButton("面包");
        JButton button7 = new JButton("蛋糕");
        JButton button8 = new JButton("苹果派");
        JButton button9 = new JButton("奶酪");
        JButton button10 = new JButton("巧克力");
        JButton button11 = new JButton("笔记本");
        JButton button12 = new JButton("电话");
        JButton button13 = new JButton("文件夹");
        JButton button14 = new JButton("钢笔");
        JButton button15 = new JButton("办公桌");
        JButton button16 = new JButton("大米");
        JButton button17 = new JButton("蔬菜");
        JButton button18 = new JButton("牛肉");
        JButton button19 = new JButton("猪肉");
        JButton button20 = new JButton("稻子");
        JButton button21 = new JButton("主板");
        JButton button22 = new JButton("内存");
        JButton button23 = new JButton("鼠标");
        JButton button24 = new JButton("显示器");
        JButton button25 = new JButton("硬盘");

        // 子面板1
        JPanel panel1 = new JPanel();
        panel1.setLayout(new BorderLayout());
        panel1.add(button1, BorderLayout.NORTH);
        panel1.add(button5, BorderLayout.SOUTH);
        panel1.add(button2, BorderLayout.EAST);
        panel1.add(button4, BorderLayout.WEST);
        panel1.add(button3, BorderLayout.CENTER);

        // 子面板2
        JPanel panel2 = new JPanel();
        panel2.setLayout(new BorderLayout());
        panel2.add(button6, BorderLayout.NORTH);
        panel2.add(button7, BorderLayout.EAST);
        panel2.add(button8, BorderLayout.CENTER);
        panel2.add(button9, BorderLayout.WEST);
        panel2.add(button10, BorderLayout.SOUTH);

        // 子面板3
        JPanel panel3 = new JPanel();
        panel3.setLayout(new BorderLayout());
        panel3.add(button11, BorderLayout.NORTH);
        panel3.add(button12, BorderLayout.EAST);
        panel3.add(button13, BorderLayout.CENTER);
        panel3.add(button14, BorderLayout.WEST);
        panel3.add(button15, BorderLayout.SOUTH);

        // 子面板4
        JPanel panel4 = new JPanel();
        panel4.setLayout(new BorderLayout());
        panel4.add(button16, BorderLayout.NORTH);
        panel4.add(button17, BorderLayout.EAST);
        panel4.add(button18, BorderLayout.CENTER);
        panel4.add(button19, BorderLayout.WEST);
        panel4.add(button20, BorderLayout.SOUTH);

        // 子面板5
        JPanel panel5 = new JPanel();
        panel5.setLayout(new BorderLayout());
        panel5.add(button21, BorderLayout.NORTH);
        panel5.add(button22, BorderLayout.EAST);
        panel5.add(button23, BorderLayout.CENTER);
        panel5.add(button24, BorderLayout.WEST);
        panel5.add(button25, BorderLayout.SOUTH);

        // 将子面板添加到主面板的五个区域
        panel.add(panel1, BorderLayout.NORTH);
        panel.add(panel2, BorderLayout.EAST);
        panel.add(panel3, BorderLayout.CENTER);
        panel.add(panel4, BorderLayout.WEST);
        panel.add(panel5, BorderLayout.SOUTH);

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

2. FlowLayout布局管理器

FlowLayout 布局管理器翻译为 流式布局管理器 ,组件从左到右(默认情况下)按顺序排列,直到当前行放不下更多的组件时,会自动换行并开始新的一行。这种布局方式很适合用来放置一些数量不定的组件,尤其是在窗口尺寸变化时能够灵活地调整。

FlowLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class FlowLayoutExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("FlowLayout测试程序");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建 FlowLayout 布局面板
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10)); // 设置水平和垂直间距
        frame.setContentPane(panel);

        // 创建按钮
        JButton button1 = new JButton("港币");
        JButton button2 = new JButton("欧元");
        JButton button3 = new JButton("英镑");
        JButton button4 = new JButton("人民币");
        JButton button5 = new JButton("美元");

        // 创建 BorderLayout 面板1
        JPanel panel1 = new JPanel();
        panel1.setLayout(new BorderLayout());
        panel1.add(button1, BorderLayout.NORTH);
        panel1.add(button2, BorderLayout.EAST);
        panel1.add(button3, BorderLayout.CENTER);
        panel1.add(button4, BorderLayout.WEST);
        panel1.add(button5, BorderLayout.SOUTH);

        JButton button6 = new JButton("主题");
        JButton button7 = new JButton("显示器");
        JButton button8 = new JButton("鼠标");
        JButton button9 = new JButton("内存");
        JButton button10 = new JButton("硬盘");

        // 创建 BorderLayout 面板2
        JPanel panel2 = new JPanel();
        panel2.setLayout(new BorderLayout());
        panel2.add(button6, BorderLayout.NORTH);
        panel2.add(button7, BorderLayout.EAST);
        panel2.add(button8, BorderLayout.CENTER);
        panel2.add(button9, BorderLayout.WEST);
        panel2.add(button10, BorderLayout.SOUTH);

        // 创建 BorderLayout 面板3
        JButton button11 = new JButton("大米");
        JButton button12 = new JButton("猪肉");
        JButton button13 = new JButton("牛肉");
        JButton button14 = new JButton("蔬菜");
        JButton button15 = new JButton("稻子");

        JPanel panel3 = new JPanel();
        panel3.setLayout(new BorderLayout());
        panel3.add(button11, BorderLayout.NORTH);
        panel3.add(button12, BorderLayout.EAST);
        panel3.add(button13, BorderLayout.CENTER);
        panel3.add(button14, BorderLayout.WEST);
        panel3.add(button15, BorderLayout.SOUTH);

        // 创建 BorderLayout 面板4
        JButton button16 = new JButton("面包");
        JButton button17 = new JButton("奶酪");
        JButton button18 = new JButton("苹果派");
        JButton button19 = new JButton("蛋糕");
        JButton button20 = new JButton("巧克力");

        JPanel panel4 = new JPanel();
        panel4.setLayout(new BorderLayout());
        panel4.add(button16, BorderLayout.NORTH);
        panel4.add(button17, BorderLayout.EAST);
        panel4.add(button18, BorderLayout.CENTER);
        panel4.add(button19, BorderLayout.WEST);
        panel4.add(button20, BorderLayout.SOUTH);

        // 创建 BorderLayout 面板5
        JButton button21 = new JButton("笔记本");
        JButton button22 = new JButton("钢笔");
        JButton button23 = new JButton("文件夹");
        JButton button24 = new JButton("电话");
        JButton button25 = new JButton("办公室");

        JPanel panel5 = new JPanel();
        panel5.setLayout(new BorderLayout());
        panel5.add(button21, BorderLayout.NORTH);
        panel5.add(button22, BorderLayout.EAST);
        panel5.add(button23, BorderLayout.CENTER);
        panel5.add(button24, BorderLayout.WEST);
        panel5.add(button25, BorderLayout.SOUTH);

        // 将所有面板加入 FlowLayout 布局的面板中
        panel.add(panel1);
        panel.add(panel2);
        panel.add(panel3);
        panel.add(panel4);
        panel.add(panel5);

        // 该方法用于自动调整窗口大小,以适应所有组件
        frame.pack();
        frame.setVisible(true);
    }
}

3. GridLayout布局管理器

GridLayout 布局管理器翻译为 网格布局管理器 ,这个布局管理器的特点像围棋盘,将内容面板分成网格的布局管理器,根据行和列数内容面板被分割出对应的格子,每个单元格的大小都是相同的。

GridLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class GridLayoutExample {
    static final int WIDTH = 300;
    static final int HEIGHT = 200;

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridLayout测试程序");
        frame.setSize(WIDTH, HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new java.awt.GridLayout(3, 2, 5, 5)); // 内容面板被分6个格子,单元格与单元格之间的水平和垂直间距5px,组件周围距离为5px
        frame.setContentPane(panel);

        JButton button1 = new JButton("港币");
        JButton button2 = new JButton("人民币");
        JButton button3 = new JButton("英镑");
        JButton button4 = new JButton("欧元");
        JButton button5 = new JButton("美元");

        // 第一个子面板使用 BorderLayout
        JPanel panel1 = new JPanel();
        panel1.setLayout(new java.awt.BorderLayout());
        panel1.add(button1, "North");
        panel1.add(button2, "West");
        panel1.add(button3, "Center");
        panel1.add(button4, "East");
        panel1.add(button5, "South");

        JButton button6 = new JButton("主板");
        JButton button7 = new JButton("内存");
        JButton button8 = new JButton("鼠标");
        JButton button9 = new JButton("显示器");
        JButton button10 = new JButton("硬盘");

        // 第二个子面板使用 BorderLayout
        JPanel panel2 = new JPanel();
        panel2.setLayout(new java.awt.BorderLayout());
        panel2.add(button6, "North");
        panel2.add(button7, "West");
        panel2.add(button8, "Center");
        panel2.add(button9, "East");
        panel2.add(button10, "South");

        JButton button11 = new JButton("大米");
        JButton button12 = new JButton("猪肉");
        JButton button13 = new JButton("牛肉");
        JButton button14 = new JButton("蔬菜");
        JButton button15 = new JButton("稻子");

        // 第三个子面板使用 FlowLayout
        JPanel panel3 = new JPanel();
        panel3.setLayout(new java.awt.FlowLayout());
        panel3.add(button11);
        panel3.add(button12);
        panel3.add(button13);
        panel3.add(button14);
        panel3.add(button15);

        JButton button16 = new JButton("面包");
        JButton button17 = new JButton("蛋糕");
        JButton button18 = new JButton("苹果派");
        JButton button19 = new JButton("奶酪");
        JButton button20 = new JButton("巧克力");

        // 第四个子面板使用 BorderLayout
        JPanel panel4 = new JPanel();
        panel4.setLayout(new java.awt.BorderLayout());
        panel4.add(button16, "North");
        panel4.add(button17, "West");
        panel4.add(button18, "Center");
        panel4.add(button19, "East");
        panel4.add(button20, "South");

        JButton button21 = new JButton("笔记本");
        JButton button22 = new JButton("电话");
        JButton button23 = new JButton("文件夹");
        JButton button24 = new JButton("钢笔");
        JButton button25 = new JButton("办公室");

        // 第五个子面板使用 BorderLayout
        JPanel panel5 = new JPanel();
        panel5.setLayout(new java.awt.BorderLayout());
        panel5.add(button21, "North");
        panel5.add(button22, "West");
        panel5.add(button23, "Center");
        panel5.add(button24, "East");
        panel5.add(button25, "South");

        // 添加各个面板到主面板
        panel.add(panel1);
        panel.add(panel2);
        panel.add(panel3);
        panel.add(panel4);
        panel.add(panel5);

        frame.pack(); // 调整窗口大小以适应组件
        frame.setVisible(true); // 显示窗口
    }
}

4. GridBagLayout布局管理器

GridBagLayout 布局管理器翻译为 网格包布局管理器Grid 代表网格,表示该布局依然是将组件放置在一个网格(行和列)中。Bag 代表包,意味着网格的大小和形状可以“包裹”组件,允许组件跨越多个单元格,形成更灵活的布局。

  • gridx:表示组件所在的列索引,从左到右,索引从 0 开始。
  • gridy:表示组件所在的行索引,从上到下,索引从 0 开始。
  • weightx (水平拉伸权重): 用于指定网格单元在水平和垂直方向上的 “拉伸权重”,如果两个组件的 weightx 分别是 1 和 2,那么它们将按照 1:2 的比例分配多余的水平空间。
  • weighty (垂直拉伸权重):用于指定网格单元在水平和垂直方向上的 “拉伸权重”,同理。
  • gridwidth:控制组件在网格中的列跨度。
  • gridheight:控制组件在网格中的行跨度。
  • anchor:控制组件在未填满的分配空间中的对齐位置。注意与 fill 配合,只有在 fill 不填充空间时(如 NONE)或组件未完全占用分配空间时,anchor 才会生效。
gridx、gridy、weightx、weighty、anchor示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class GridBagLayoutExample1 {
    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagConstraints.weightx 和 weighty 示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);

        // 设置布局管理器
        frame.setLayout(new java.awt.GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        // 添加第一个按钮
        JButton button1 = new JButton("Button 1");
        gbc.gridx = 0; // 第一列
        gbc.gridy = 0; // 第一行
        gbc.weightx = 0.5; // 水平权重
        gbc.weighty = 0.5; // 垂直权重
        gbc.fill = GridBagConstraints.BOTH; // 填充水平和垂直空间
        frame.add(button1, gbc);

        // 添加第二个按钮
        JButton button2 = new JButton("Button 2");
        gbc.gridx = 1; // 第二列
        gbc.gridy = 0; // 第一行
        gbc.weightx = 1.5; // 水平权重较大
        gbc.weighty = 0.5; // 垂直权重
        frame.add(button2, gbc);

        // 添加第三个按钮
        JButton button3 = new JButton("Button 3");
        gbc.gridx = 0; // 第一列
        gbc.gridy = 1; // 第二行
        gbc.weightx = 0.5; // 水平权重
        gbc.weighty = 1.0; // 垂直权重较大
        frame.add(button3, gbc);

        // 添加第四个按钮
        JButton button4 = new JButton("Button 4");
        gbc.gridx = 1; // 第二列
        gbc.gridy = 1; // 第二行
        gbc.weightx = 1.5; // 水平权重较大
        gbc.weighty = 1.0; // 垂直权重较大
        frame.add(button4, gbc);

        frame.setVisible(true);
    }
}
GridBagLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class GridBagLayoutExample2 {
    static final int WIDTH = 600;
    static final int HEIGHT = 450;

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayout测试程序");
        frame.setSize(WIDTH, HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        panel.setLayout(new java.awt.GridBagLayout());
        frame.setContentPane(panel);

        JLabel label1 = new JLabel("布局管理器测试窗口");
        JLabel label2 = new JLabel("用户名");
        JLabel label3 = new JLabel("密码");

        JTextField textField1 = new JTextField(15);
        JTextField textField2 = new JTextField(15);

        JButton button1 = new JButton("确定");
        JButton button2 = new JButton("放弃");

        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.NONE;

        // 设置窗口在屏幕中央显示
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension dimension = toolkit.getScreenSize();
        frame.setLocation(dimension.width / 2 - WIDTH / 2, dimension.height / 2 - HEIGHT / 2);

        // 调用 add 方法添加组件
        addComponent(panel, label1, 0, 0, 2, 1, GridBagConstraints.CENTER);
        addComponent(panel, label2, 0, 1, 1, 1, GridBagConstraints.EAST);
        addComponent(panel, label3, 0, 2, 1, 1, GridBagConstraints.EAST);
        addComponent(panel, textField1, 1, 1, 1, 1);
        addComponent(panel, textField2, 1, 2, 1, 1);
        addComponent(panel, button1, 0, 3, 1, 1, GridBagConstraints.CENTER);
        addComponent(panel, button2, 1, 3, 1, 1, GridBagConstraints.EAST);

        frame.setResizable(false);
        frame.setVisible(true);
    }

    // 定义 addComponent 方法
    public static void addComponent(Container container, Component c, int x, int y, int w, int h) {
        addComponent(container, c, x, y, w, h, GridBagConstraints.CENTER); // 默认居中
    }

    // 定义 addComponent 方法,添加间距和其他属性
    public static void addComponent(Container container, Component c, int x, int y, int w, int h, int anchor) {
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.gridwidth = w;
        gbc.gridheight = h;
        gbc.anchor = anchor;
        gbc.insets = new Insets(10, 10, 10, 10); // 设置组件与组件之间的间距
        container.add(c, gbc);
    }
}

5. CardLayout布局管理器

CardLayout 布局管理器翻译为 卡片布局管理器 ,内容面板设为卡片布局后,面容面板内的每一个组件当做一个卡片,一次仅有一个组件可见,并且可以动态的切换组件。

代码CardLayout布局管理器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class CardLayoutExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("CardLayout Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLayout(new BorderLayout());

        // 创建 CardLayout 和容器
        java.awt.CardLayout cardLayout = new java.awt.CardLayout();
        JPanel cardPanel = new JPanel(cardLayout);

        // 设置卡片面板的边框,添加内边距
        cardPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        // 创建 3 个卡片
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.RED);
        panel1.add(new JLabel("Panel 1"));

        JPanel panel2 = new JPanel();
        panel2.setBackground(Color.BLUE);
        panel2.add(new JLabel("Panel 2"));

        JPanel panel3 = new JPanel();
        panel3.setBackground(Color.GREEN);
        panel3.add(new JLabel("Panel 3"));

        // 将卡片加入容器
        cardPanel.add(panel1, "1");
        cardPanel.add(panel2, "2");
        cardPanel.add(panel3, "3");

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        JButton prevButton = new JButton("上一步");
        JButton nextButton = new JButton("下一步");
        JButton btn1 = new JButton("1");
        JButton btn2 = new JButton("2");
        JButton btn3 = new JButton("3");

        // 调整按钮 1、2、3 的内边距(Insets)
        btn1.setMargin(new Insets(2, 5, 2, 5)); // 上下左右边距
        btn2.setMargin(new Insets(2, 5, 2, 5));
        btn3.setMargin(new Insets(2, 5, 2, 5));

        buttonPanel.add(prevButton);
        buttonPanel.add(btn1);
        buttonPanel.add(btn2);
        buttonPanel.add(btn3);
        buttonPanel.add(nextButton);

        // 按钮功能实现
        prevButton.addActionListener(e -> cardLayout.previous(cardPanel));
        nextButton.addActionListener(e -> cardLayout.next(cardPanel));
        btn1.addActionListener(e -> cardLayout.show(cardPanel, "1"));
        btn2.addActionListener(e -> cardLayout.show(cardPanel, "2"));
        btn3.addActionListener(e -> cardLayout.show(cardPanel, "3"));

        // 添加组件到 JFrame
        frame.add(cardPanel, BorderLayout.CENTER);
        frame.add(buttonPanel, BorderLayout.SOUTH);

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

6. BoxLayout布局管理器

BoxLayout 布局管理器翻译为 箱式布局管理器 ,可将内容面板设置为垂直排列组件或水平排列组件,它是将组件沿着指定轴(水平或垂直)排列的一种布局管理器,常用于创建垂直或水平排列的组件。

BoxLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class BoxLayoutExample {
    public static void main(String[] args) {
        // 创建主框架
        JFrame frame = new JFrame("BoxLayout 示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);

        // 创建主面板,使用 BoxLayout 垂直排列组件
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

        // 添加顶部间隔
        mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); // 上边框间隔

        // 创建姓名标签和文本框
        JPanel namePanel = new JPanel();
        namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.X_AXIS));
        JLabel nameLabel = new JLabel("姓名:");
        JTextField nameField = new JTextField();
        nameField.setMaximumSize(new Dimension(100, 25)); // 限制宽度
        namePanel.add(nameLabel);
        namePanel.add(Box.createRigidArea(new Dimension(10, 0))); // 添加间隔
        namePanel.add(nameField);

        // 创建密码标签和文本框
        JPanel passwordPanel = new JPanel();
        passwordPanel.setLayout(new BoxLayout(passwordPanel, BoxLayout.X_AXIS));
        JLabel passwordLabel = new JLabel("密码:");
        JPasswordField passwordField = new JPasswordField();
        passwordField.setMaximumSize(new Dimension(100, 25)); // 限制宽度
        passwordPanel.add(passwordLabel);
        passwordPanel.add(Box.createRigidArea(new Dimension(10, 0))); // 添加间隔
        passwordPanel.add(passwordField);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
        JButton okButton = new JButton("确定");
        JButton cancelButton = new JButton("取消");
        buttonPanel.add(Box.createHorizontalGlue()); // 左侧弹性间隔
        buttonPanel.add(okButton);
        buttonPanel.add(Box.createRigidArea(new Dimension(10, 0))); // 添加按钮间隔
        buttonPanel.add(cancelButton);
        buttonPanel.add(Box.createHorizontalGlue()); // 右侧弹性间隔

        // 将各部分添加到主面板
        mainPanel.add(namePanel);
        mainPanel.add(Box.createRigidArea(new Dimension(0, 10))); // 垂直间隔
        mainPanel.add(passwordPanel);
        mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); // 垂直间隔
        mainPanel.add(buttonPanel);

        // 添加主面板到框架
        frame.add(mainPanel);

        // 设置框架可见
        frame.setVisible(true);
    }
}

7. SpringLayout布局管理器

SpringLayout 布局管理器翻译为 弹簧布局管理器 ,这种布局管理器通过设置组件之间的约束关系来定位组件,设置组件的边界(如上、下、左、右)相对于容器边界或其他组件的距离。

SpringLayout布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class SpringLayoutExample {
    public static void main(String[] args) {
        // 创建主框架
        JFrame frame = new JFrame("SpringLayout 示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);

        // 创建面板,使用 SpringLayout 布局管理器
        JPanel panel = new JPanel();
        SpringLayout layout = new SpringLayout();
        panel.setLayout(layout);

        // 创建组件
        JLabel label = new JLabel("这是一个标签");
        JButton button1 = new JButton("按钮 1");
        JButton button2 = new JButton("按钮 2");

        // 将组件添加到面板
        panel.add(label);
        panel.add(button1);
        panel.add(button2);

        // 设置 label 左边界被设置为距离 panel 的左边界 50 像素
        layout.putConstraint(SpringLayout.WEST, label, 50, SpringLayout.WEST, panel);

        // 设置 label 上边界被设置为距离 panel 的上边界 30 像素
        layout.putConstraint(SpringLayout.NORTH, label, 30, SpringLayout.NORTH, panel);

        // 设置 button1 左边界距离 panel 的左边界 50 像素
        layout.putConstraint(SpringLayout.WEST, button1, 50, SpringLayout.WEST, panel);

        // 设置 button1 上边界距离 label 下边界 20 像素
        layout.putConstraint(SpringLayout.NORTH, button1, 20, SpringLayout.SOUTH, label);

        // 设置 button2 左边界距离 panel 左边界 25 像
        layout.putConstraint(SpringLayout.WEST, button2, 25, SpringLayout.WEST, panel);

        // 设置 button2 上边界距离 button1 下边界 50 像素
        layout.putConstraint(SpringLayout.NORTH, button2, 50, SpringLayout.SOUTH, button1);

        // 将面板添加到框架
        frame.add(panel);

        // 设置框架可见
        frame.setVisible(true);
    }
}

8. GroupLayout布局管理器

GroupLayout 布局管理器翻译为 组布局管理器 ,这种布局管理器特点是把多组件按区域划分到不同的Group中,再根据各Group相对水平轴和垂直轴的排列方式管理组件。

代码GroupLayout布局管理器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class GroupLayoutExample {
    public static void main(String[] args) {
        // 创建主窗体
        JFrame frame = new JFrame("GroupLayout 示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 200);

        // 创建一个 JPanel
        JPanel panel = new JPanel();

        // 使用 GroupLayout 布局管理器
        GroupLayout layout = new GroupLayout(panel);
        panel.setLayout(layout);

        // 创建文本框和按钮
        JTextField textField = new JTextField("文本", 10);
        JButton button1 = new JButton("按钮1");
        JButton button2 = new JButton("按钮2");

        // 设置水平和垂直的自动拉伸
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);

        // 水平布局:文本框在最左边,按钮 button1 和 button2 按顺序从左到右排列,且它们在同一行
        layout.setHorizontalGroup(
                layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                                .addComponent(textField)
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(button1)
                                        .addComponent(button2))));

        // 垂直布局:文本框放在顶部,按钮 button1 和 button2 会放在下一行,并且是基线对齐
        layout.setVerticalGroup(
                layout.createSequentialGroup()
                        .addComponent(textField)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(button1)
                                .addComponent(button2)));

        // 将面板添加到窗体中并显示
        frame.add(panel);
        frame.setVisible(true);
    }
}

9. 自定义布局管理器

自定义布局管理器需要继承 LayoutManager 接口,并实现其方法。

自定义布局管理器示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public class CustomLayoutExample {
    public static void main(String[] args) {
        // 创建主窗体
        JFrame frame = new JFrame("自定义布局管理器 示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);

        // 创建面板并设置自定义布局管理器
        JPanel panel = new JPanel(new CustomLayout());

        // 创建组件
        JButton button1 = new JButton("按钮1");
        JButton button2 = new JButton("按钮2");
        JLabel label1 = new JLabel("标签1");
        JLabel label2 = new JLabel("标签2");
        JTextField textField1 = new JTextField(20);
        JTextField textField2 = new JTextField(20);

        // 添加组件到面板
        panel.add(button1);
        panel.add(button2);
        panel.add(label1);
        panel.add(label2);
        panel.add(textField1);
        panel.add(textField2);

        // 将面板添加到窗口
        frame.add(panel);
        frame.setVisible(true);
    }
}

// 自定义布局管理器
class CustomLayout implements LayoutManager {

    // 设置组件之间的垂直间距
    private static final int VERTICAL_GAP = 10;
    private static final int HORIZONTAL_GAP = 10;

    @Override
    public void addLayoutComponent(String name, Component comp) {
        // 不需要处理
    }

    @Override
    public void removeLayoutComponent(Component comp) {
        // 不需要处理
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        int width = 0;
        int height = 0;

        // 遍历容器中的所有组件
        for (Component comp : parent.getComponents()) {
            Dimension d = comp.getPreferredSize();
            width = Math.max(width, d.width); // 取最大宽度
            height += d.height + VERTICAL_GAP; // 累加所有组件的高度,并加上间距
        }

        // 返回容器的首选尺寸(宽度和高度)
        return new Dimension(width + 2 * HORIZONTAL_GAP, height + VERTICAL_GAP);
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        int width = 0;
        int height = 0;

        for (Component comp : parent.getComponents()) {
            Dimension d = comp.getMinimumSize();
            width = Math.max(width, d.width); // 获取最大的最小宽度
            height += d.height + VERTICAL_GAP; // 累加所有组件的最小高度,并加上间距
        }

        // 返回容器的最小尺寸(宽度和高度)
        return new Dimension(width + 2 * HORIZONTAL_GAP, height + VERTICAL_GAP);
    }

    @Override
    public void layoutContainer(Container parent) {
        int y = 0; // 初始y坐标

        // 遍历面板中的所有组件,设置每个组件的位置
        for (Component comp : parent.getComponents()) {
            Dimension d = comp.getPreferredSize();
            comp.setBounds(HORIZONTAL_GAP, y, d.width, d.height); // 设置组件的位置和大小
            y += d.height + VERTICAL_GAP; // 更新y坐标,给下一个组件预留空间
        }
    }
}

总结

本文主要介绍了JavaSwingGui的基本框架,基本概念,以及如何使用布局管理器来管理组件的位置和大小。整体概念和布局管理器是重点,理解了布局管理器,对JavaSwingGui的布局管理具有更深刻的理解。