背景

首先本文是一个系列的文章,起名为《Java Swing GUi从小白到大神》,主要介绍Java Swing相关概念和实践应用。目前JavaSwingGUI很少作为界面的开发框架,但是对于学习Java体系,以及新手将来学习后端之后,能快速从前后端整体去理解一套系统是非常有帮助的,所以是很有必要学习和掌握的。本篇是系列博文的第一篇,让我们开始吧。

文章概览

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

1.Java Swing组件基础

1.1 Swing组件的层次
这里简单介绍Swing组件的层次,实际有很多,不详细介绍,只是把主要层次列出来。

 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
java.awt.Component
└── java.awt.Container
    ├── javax.swing.JComponent
    │   ├── 中间容器组件
    │   │   ├── JPanel
    │   │   ├── JScrollPane
    │   │   ├── JSplitPane
    │   │   ├── JTabbedPane
    │   │   ├── JToolBar
    │   │   ├── JLayeredPane
    │   │   ├── JDesktopPane
    │   │   ├── JTable
    │   │   ├── JTree
    │   │   └── JInternalFrame
    │   └── 普通组件
    │       ├── JButton
    │       ├── JCheckBox
    │       ├── JRadioButton
    │       ├── JTextField
    │       ├── JTable
    │       ├── JTree
    │       ├── JComboBox
    │       └── JProgressBar
    └── 顶级组件
        ├── JFrame
        ├── JDialog
        ├── JApplet
        └── JWindow

顶级组件列表:

  • 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
    

中间容器列表:

  • JPanel:
    • 用作面板容器,最常用的中间容器。
    • 通常与布局管理器配合使用。
  • JScrollPane:
    • 滚动面板,用于支持内容的滚动显示。
    • 常用来包装大内容的组件,例如表格、列表或文本区域。
  • JSplitPane:
    • 分割面板,用于将界面分为两个区域,可调整大小。
  • JTabbedPane:
    • 卡片面板,用于在同一区域切换多个选项卡。
  • JToolBar:
    • 工具栏,用于组织快捷操作按钮。
  • JLayeredPane:
    • 层叠面板,用于管理组件的 Z 轴顺序(层次)。
  • JDesktopPane:
    • 虚拟桌面容器,用于管理内部窗口(JInternalFrame)。
  • JInternalFrame:
    • 内部窗口,通常嵌套在 JDesktopPane 中。
  • 特点:
    • 直接继承自 javax.swing.JComponent。
    • 主要用于分组和布局子组件。

普通组件列表:

  • 按钮类:
    • 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 配合使用。

1.3 向顶层容器中添加内容面板和菜单

代码添加内容面板和菜单
 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
public class HelloWorld {
    static final int WIDTH = 300;
    static final int HEIGHT = 200;

    public static void main(String[] args) {
        JFrame jf = new JFrame();
        // 设置窗口大小
        jf.setSize(WIDTH, HEIGHT);
        // 设置窗口关闭操作,确保程序退出
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置窗口标题
        jf.setTitle("学生管理系统");

        // 创建一个菜单栏
        JMenuBar menuBar1 = new JMenuBar();
        // 将菜单栏设置到窗口
        jf.setJMenuBar(menuBar1);
        // 创建三个菜单
        JMenu menu1 = new JMenu("文件");
        JMenu menu2 = new JMenu("编辑");
        JMenu menu3 = new JMenu("视图");

        // 将菜单添加到菜单栏
        menuBar1.add(menu1);
        menuBar1.add(menu2);
        menuBar1.add(menu3);

        // 创建菜单项
        JMenuItem item1 = new JMenuItem("打开");
        JMenuItem item2 = new JMenuItem("保存");
        JMenuItem item3 = new JMenuItem("打印");

        // 将菜单项添加到“文件”菜单中,并添加一个分隔符
        menu1.add(item1);
        menu1.add(item2);
        menu1.addSeparator();
        menu1.add(item3);

        // 显示窗口
        jf.setVisible(true);
        // 创建一个按钮用于测试
        JButton jb = new JButton("这是一个测试按钮组件");
        // 创建一个面板用于放置按钮
        JPanel jp = new JPanel();
        jp.add(jb);
        // 将面板设置为窗口的内容面板
        jf.setContentPane(jp);
    }
}

1.4 JComponent类
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
代码按钮添加边框
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Container3 {
    static final int WIDTH = 300;
    static final int hEIGHT = 200;

    public static void main(String[] args) {
        JFrame frame = new JFrame("添加内容面板测试程序");
        frame.setSize(WIDTH, hEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        JPanel panel = new JPanel();
        frame.setContentPane(panel);

        JButton button1 = new JButton("确认");
        JButton button2 = new JButton("取消");

        panel.add(button1);
        panel.add(button2);

        button1.setBorder(BorderFactory.createLineBorder(Color.RED));
    }
}

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
32
33
34
35
36
37
38
39
public class LableAndButton {
    static final int WIDTH = 300;
    static final int hEIGHT = 200;

    public static void main(String[] args) {
        JFrame frame = new JFrame("如何使用按钮和标签");
        frame.setSize(WIDTH, hEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        frame.setContentPane(panel);

        JLabel label = new JLabel("张三");
        panel.add(label);

        JRadioButton radioButton1 = new JRadioButton("男");
        JRadioButton radioButton2 = new JRadioButton("女");

        ButtonGroup group = new ButtonGroup();
        group.add(radioButton1);
        group.add(radioButton2);

        panel.add(radioButton1);
        panel.add(radioButton2);

        JLabel label2 = new JLabel("兴趣爱好");
        JCheckBox checkBox1 = new JCheckBox("足球");
        JCheckBox checkBox2 = new JCheckBox("篮球");
        JCheckBox checkBox3 = new JCheckBox("游泳");
        JCheckBox checkBox4 = new JCheckBox("跑步");
        panel.add(label2);
        panel.add(checkBox1);
        panel.add(checkBox2);
        panel.add(checkBox3);
        panel.add(checkBox4);

        frame.setVisible(true);
    }
}

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

首选,布局管理器是针对内容面板进行布局的,在使用的时候根据实际情况选择,下面是介绍一些常用的布局管理器。

3.1 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
public class BoderLayout {
    static final int WIDTH = 300;
    static final int hEIGHT = 200;

    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 java.awt.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("硬盘");

        JPanel panel1 = new JPanel();
        panel1.setLayout(new java.awt.BorderLayout());
        panel1.add(button1, "North");
        panel1.add(button5, "South");
        panel1.add(button2, "East");
        panel1.add(button4, "West");
        panel1.add(button3, "Center");

        JPanel panel2 = new JPanel();
        panel2.setLayout(new java.awt.BorderLayout());
        panel2.add(button6, "North");
        panel2.add(button7, "East");
        panel2.add(button8, "Center");
        panel2.add(button9, "West");
        panel2.add(button10, "South");

        JPanel panel3 = new JPanel();
        panel3.setLayout(new java.awt.BorderLayout());
        panel3.add(button11, "North");
        panel3.add(button12, "East");
        panel3.add(button13, "Center");
        panel3.add(button14, "West");
        panel3.add(button15, "South");

        JPanel panel4 = new JPanel();
        panel4.setLayout(new java.awt.BorderLayout());
        panel4.add(button16, "North");
        panel4.add(button17, "East");
        panel4.add(button18, "Center");
        panel4.add(button19, "West");
        panel4.add(button20, "South");

        JPanel panel5 = new JPanel();
        panel5.setLayout(new java.awt.BorderLayout());
        panel5.add(button21, "North");
        panel5.add(button22, "East");
        panel5.add(button23, "Center");
        panel5.add(button24, "West");
        panel5.add(button25, "South");

        panel.add(panel1, "North");
        panel.add(panel2, "East");
        panel.add(panel3, "Center");
        panel.add(panel4, "West");
        panel.add(panel5, "South");

        frame.setVisible(true);
    }
}

3.2 FlowLayout布局管理器
这个布局管理器的特点是按照控件加入的顺序从左到右排列,一行排满,再换下一行,另外如果有些按钮看不到,可以使用pack方法自动调整Frame的大小,代码展示。

  • JFrame.pack() 是 Java Swing 中用于自动调整窗口大小的方法。调用该方法后,窗口的大小会调整到能够正好容纳其中所有组件及其首选大小的程度,并考虑到布局管理器设置的间距和边框。
代码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
public class FlowLayoutAndBorderLayout {
    static final int WIDTH = 300;
    static final int hEIGHT = 200;

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

        JPanel panel = new JPanel();
        panel.setLayout(new java.awt.FlowLayout());
        frame.setContentPane(panel);

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

        JPanel panel1 = new JPanel();
        panel1.setLayout(new java.awt.BorderLayout());
        panel1.add(button1, "North");
        panel1.add(button2, "East");
        panel1.add(button3, "Center");
        panel1.add(button4, "West");
        panel1.add(button5, "South");

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

        JPanel panel2 = new JPanel();
        panel2.setLayout(new java.awt.BorderLayout());
        panel2.add(button6, "North");
        panel2.add(button7, "East");
        panel2.add(button8, "Center");
        panel2.add(button9, "West");
        panel2.add(button10, "South");

        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 java.awt.BorderLayout());
        panel3.add(button11, "North");
        panel3.add(button12, "East");
        panel3.add(button13, "Center");
        panel3.add(button14, "West");
        panel3.add(button15, "South");

        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 java.awt.BorderLayout());
        panel4.add(button16, "North");
        panel4.add(button17, "East");
        panel4.add(button18, "Center");
        panel4.add(button19, "West");
        panel4.add(button20, "South");

        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 java.awt.BorderLayout());
        panel5.add(button21, "North");
        panel5.add(button22, "East");
        panel5.add(button23, "Center");
        panel5.add(button24, "West");
        panel5.add(button25, "South");

        panel.add(panel1);
        panel.add(panel2);
        panel.add(panel3);
        panel.add(panel4);
        panel.add(panel5);

        frame.pack();
        frame.setVisible(true);
    }
}

3.3 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
public class GridAndFlowAndBorder {
    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, 3));
        frame.setContentPane(panel);

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

        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("硬盘");

        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("稻子");

        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("巧克力");

        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("办公室");

        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");

        JPanel panel6 = new JPanel();

        panel.add(panel1);
        panel.add(panel2);
        panel.add(panel3);
        panel.add(panel4);
        panel.add(panel5);
        panel.add(panel6);

        frame.pack();
        frame.setVisible(true);
    }
}

3.4 GridBagLayout布局管理器

GridBagLayout布局管理器是Java Swing提供的一种布局管理器,它提供了一种灵活的方式来排列和定位组件。GridBagLayout布局管理器使用网格来定位组件,每个组件都被分配到一个或几个网格单元中,并使用网格行列来确定组件的位置。网格的划分是虚拟的,只有在放置组件时,网格才会被显式创建。GridBagLayout布局管理器提供了许多属性,如组件的权重、填充、 Insets、 Anchor 等,这些属性可以控制组件的位置和布局。

  • 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 GridBagLayoutWeightExample {
    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
public class GridBagLayout {
    static final int WIDTH = 300;
    static final int HEIGHT = 150;

    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.EAST);
        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);
        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; // 设置 anchor 属性
        container.add(c, gbc);
    }
}

3.5 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 CardLayout {
    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);
    }
}
3.6 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);
    }
}

3.7 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
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);

        // 设置 SpringLayout 的约束
        // label 的位置
        layout.putConstraint(SpringLayout.WEST, label, 50, SpringLayout.WEST, panel); // 距离左边 50 像素
        layout.putConstraint(SpringLayout.NORTH, label, 30, SpringLayout.NORTH, panel); // 距离上边 30 像素

        // button1 的位置
        layout.putConstraint(SpringLayout.WEST, button1, 50, SpringLayout.WEST, panel); // 距离左边 50 像素
        layout.putConstraint(SpringLayout.NORTH, button1, 20, SpringLayout.SOUTH, label); // 距离 label 下面 20 像素

        // button2 的位置
        layout.putConstraint(SpringLayout.WEST, button2, 50, SpringLayout.WEST, panel); // 距离左边 50 像素
        layout.putConstraint(SpringLayout.NORTH, button2, 20, SpringLayout.SOUTH, button1); // 距离 button1 下面 20 像素

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

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

3.8 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);

        // 配置水平布局(从左到右的顺序)
        layout.setHorizontalGroup(
                layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                                .addComponent(textField)
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(button1)
                                        .addComponent(button2))));

        // 配置垂直布局(从上到下的顺序)
        layout.setVerticalGroup(
                layout.createSequentialGroup()
                        .addComponent(textField)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(button1)
                                .addComponent(button2)));

        // 将面板添加到窗体中并显示
        frame.add(panel);
        frame.setVisible(true);
    }
}
3.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的布局管理具有更深刻的理解。