在Java中使用网格袋布局
从控制台应用过渡到GUI应用,对于新晋开发者来说是一个非常具有挑战性的目标。当你发现GUI只有在你知道如何使用、何时使用和使用什么时才会有乐趣时,挑战就来了。
简介
知道如何在屏幕上定位你的GUI组件和使用正确的布局是一项繁琐的任务,也是Java中GUI编程的一个重要方面。在这篇文章中,我们将深入探讨在Java中实现GridBag布局,以及如何使用它来实现理想的用户界面(UI)。
前提条件
读者需要具备以下条件
- 对Java的基本编程有一定的了解。
- 对Java中的OOP原则有基本了解。
- 在你的机器上安装好Java和一个合适的集成开发环境(IDE)。我推荐使用NetBeans,因为我们将在本教程中使用它。
目标
在本教程结束时,读者将。
- 熟悉Java中不同类型的布局管理器。
- 对Java中的Gridbag布局有深入了解。
- 知道何时、为何以及如何在Java中使用Gridbag布局。
网格袋布局
在一个容器中安排组件
Java提供了不同的选项来定位容器中的组件,其中包括。
- 绝对定位。这让你对面板上的组件的大小和位置有绝对控制。它允许你明确指定每个组件的大小和位置。
你可以通过将容器的布局管理器设置为null 来实现绝对定位。即setLayout(null); 。而且还可以将每个组件的容器setSize 和setBounds 方法设置为任何需要的值。
- 视觉编程。这是一个GUI设计工具,允许你从一组组件中拖放组件到IDE的设计区。这些组件通常位于IDE的侧边栏。你可以在IDE的组件工具箱中找到它们。
我们可以修改它们以适应设计需要。你也可以在设计完成后给这些组件添加事件处理代码。事件处理代码为组件添加功能。在所有的设计过程中,IDE都会为GUI创建代码,所以你以后可以根据任何需要来修改它。
- 布局管理器。这涉及到使用定义的或定制的布局来定位面板或框架上的组件。布局管理器在确定组件的大小方面提供了更多的灵活性。但对每个组件的绝对位置的控制较少。
什么是布局管理器
布局管理器负责在其框架或面板中定位每个GUI组件。布局管理器允许你在所需的位置对齐组件。与其为它们的确切位置而烦恼,我们不如用一些特定的约束条件将它们布置在面板上,由布局管理器负责定位。
布局管理器的类型
下面是Java提供的一些布局管理器。
- 流动布局
- 边框布局
- 框式布局
- 网格布局
- 组布局
- GridBag布局
在这篇文章中,我们将考虑Gridbag布局,并利用它建立一个惊人的用户界面。
什么是GridBag布局管理器
Gridbag布局管理器将组件放在与网格布局类似的行和列中。但在Gridbag布局中,你可以指定每行或每列的大小。你还可以决定一个组件是否跨越许多行或列。
Gridbag布局是Java提供的所有布局管理器中最灵活但最复杂的一种。它被用来构建复杂的UI,也是使用最多的布局管理器之一。在处理不同尺寸的组件时,那么Gridbag布局是一个理想的选择。
Gridbag布局以包含行和列的表格形式表示每个组件的位置。组件的位置是用网格线勾勒出来的,就像下面的图片一样。

在用Gridbag布局进行编码之前,最好先用网格线勾勒出面板中的组件。这将使你对面板上每个组件的位置有一个直观的了解。从上面的图片可以看出,有些组件只占用一个网格,而有些则占用多个网格。
这意味着这些组件不需要有相同的尺寸。你可以使用本文后面要考虑的GridBagConstraints 对象的gridweight 和gridheight 方法来指定一个组件跨越多少个网格。
使用GridBag布局工作
现在,让我们分析一下上面的图片,考虑每个组件、x和y的位置以及跨度。
| 组件 | x | y | 跨度 |
|---|---|---|---|
| 组合框 "Easy" | 0 | 0 | 1 |
| 组合框 "乘法" | 2 | 0 | 1 |
| 文本字段1 | 0 | 1 | 3 |
| 文本字段2 | 1 | 2 | 1 |
| 按钮 "开始" | 0 | 3 | 1 |
| 按钮 "进入"。 | 1 | 3 | 1 |
| 按钮 "停止" | 2 | 3 | 1 |
面板左上角的第一个元素位于(0,0)的位置。这是布局的起点,其他每一个组件都在其后。从上面的例子来看,"Easy "复选框就位于这个第一位置。它只跨越了1列,这是在表中指定的。
跨度指定一个组件占据多少个单元格。默认是1。
在本教程中,为了清楚起见,我们将在定义中明确加入1。网格的下一个组件是位于(2,0)位置的 "乘法 "复选框。你可以在第2列找到它,和 "轻松 "复选框一样,它也跨越了1列。
但是,注意这两个复选框之间的空间,这是Gridbag布局的强大功能之一。这些元素的间距是均匀的,每个元素都如愿以偿地坐落在各自的位置上。下一个组件是Textfield1,它位于(0,1)。
你可以在第0列和第1行找到这个组件。 它也跨越了三列。事实上,它横跨第2列和第3列在定义中并不重要。在布置组件时要考虑的一个重要问题是起始位置。
我们可以根据需要将组件设置为跨越多少行和列。根据它跨越的方向,它不会影响位于当前单元格旁边的其他单元格。其他组件以同样的顺序跟随,每个组件跨越一个单元格。Textfield2位于(1,2),按钮 "开始 "位于(0,3),按钮 "输入 "位于(1,3),按钮 "停止 "位于(2,3)。
设置面板的布局
我们像其他布局管理器一样,将Gridbag布局设置为我们面板的布局。这是通过将一个GridBagLayout 的对象传入面板setLayout 方法来完成的,如下所示。
panel1 = new JPanel();
panel1.setLayout(new GridBagLayout());
另一种可以用来设置面板布局的方法是在面板实例对象构造函数中传递布局对象作为参数,如下图所示。
panel1 = new JPanel(new GridBagLayout());
这两种方法都很好用,但为了清楚起见,建议使用第一种方法。
GridBag约束
我们使用Gridbag约束来确定面板中每个组件的大小和位置。因此,面板中的每个元素都有一些特性,这些特性是由Gridbag约束条件定义的。下面列出了GridBagConstraints 类中一些常用的方法。
| 字段 | 功能 |
|---|---|
| int gridx | 元素的列 |
| int gridy | 组件的行 |
| int gridwidth | 组件跨度的列数 |
| int gridheight | 组件所跨的行数 |
| int 填充 | 一个常数,决定组件如何处理单元格中的剩余空间。 |
| int anchor | 一个常数,决定组件在没有填满单元格时的放置位置。 |
| insets ins | 决定每个组件周围的填充物 |
为组件添加约束的方法
我们要考虑的第一个方法是创建一个GridBagConstraints 对象。然后将该约束对象与组件一起添加到面板中。你可以使用这个约束对象为其他组件添加约束,但在必要时对象的字段会被改变。
下面是一个例子。
panel1 = new JPanel();
panel1.setLayout(new GridBagLayout());
textField1 = new JTextField(33);
textField2 = new JTextField(3);
GridBagConstraints constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 1;
constr.gridheight = 1;
constr.gridwidth = 3;
constr.anchor = GridBagConstraint.CENTER;
panel1.add(textField1, constr);
constr.gridx = 1;
constr.gridy = 2;
constr.gridwidth = 1;
panel1.add(textField2, constr);
上面的片段创建了一个单一的约束对象,并使用它将两个组件添加到面板中。注意,在向textField1添加约束之前,所有必要的字段都被填满。然后在添加到textField2之前,约束字段被修改。使用这种方法,只改变必要的字段以避免重复。
第二种方法是创建一个辅助方法,为约束条件的每个字段调用和传递值。例如,下面的片段使用add 方法将约束添加到一个组件,然后添加到面板。
public static void add(JPanel panel, JComponent comp, int x, int y, int width, int height) {
GridBagConstraints constr = new GridBagConstraints();
constr.gridx = x;
constr.gridy = y;
constr.gridheight = height;
constr.gridwidth = width;
constr.insets = new Insets(2, 2, 2, 2);
constr.anchor = GridBagConstraints.CENTER;
constr.fill = GridBagConstraints.BOTH;
panel.add(comp, constr);
}
然后,每当你需要向面板添加一个组件时,就会调用这个方法。你必须传入所有的参数才能成功添加组件。
比如说。
add(panel1, textField1, 0, 1, 3, 1);
在需要添加更多约束的情况下,那么在方法的参数中指定这些约束。
CAL的用户界面

上面的用户界面(UI)是一个很好的例子,展示了Gridbag布局的能力。让我们使用Gridbag布局来构建用户界面。
import java.awt.*;
import javax.swing.*;
public class CAL extends JFrame {
static JButton start, stop, enter;
static JComboBox<String> level, type;
static final String[] levelList = {"Easy", "Medium", "Hard"};
static final String[] typeList = {"Multiply", "Add", "Subtract", "Divide", "Random"};
static JTextField question, answer;
static JPanel panel;
// helper method to add component to the panel
public static void addComponent(JPanel p, JComponent comp, int x, int y, int width, int height) {
GridBagConstraints constr = new GridBagConstraints();
constr.gridx = x;
constr.gridy = y;
constr.gridheight = height;
constr.gridwidth = width;
constr.weightx = 2.0;
constr.weighty = 1.0;
constr.insets = new Insets(1, 1, 1, 1);
constr.anchor = GridBagConstraints.CENTER;
constr.fill = GridBagConstraints.BOTH;
p.add(comp, constr);
}
public CAL() {
super("Computer Assisted Learning"); // title of GUI
panel = new JPanel();
panel.setLayout(new GridBagLayout()); // set panel's layout
// initialize components
start = new JButton("Start");
stop = new JButton("Stop");
enter = new JButton("Enter");
answer = new JTextField(3);
question = new JTextField("Press start to begin", 33);
level = new JComboBox<>(levelList);
type = new JComboBox<>(typeList);
// disabled textField
question.setEnabled(false);
// style components
start.setFont(new Font("Monospaced", Font.BOLD, 16));
stop.setFont(new Font("Monospaced", Font.BOLD, 16));
enter.setFont(new Font("Monospaced", Font.BOLD, 18));
level.setFont(new Font("Monospaced", Font.PLAIN, 16));
type.setFont(new Font("Monospaced", Font.PLAIN, 16));
question.setFont(new Font("Monospaced", Font.BOLD, 19));
answer.setFont(new Font("Monospaced", Font.BOLD, 21));
answer.setHorizontalAlignment(JTextField.CENTER);
// adds components to panel using helper method
addComponent(panel, level, 0, 0, 1, 1);
addComponent(panel, type, 2, 0, 1, 1);
addComponent(panel, question, 0, 1, 3, 1);
addComponent(panel, start, 0, 3, 1, 1);
addComponent(panel, answer, 1, 2, 1, 1);
addComponent(panel, stop, 2, 3, 1, 1);
addComponent(panel, enter, 1, 3, 1, 1);
// adds panel to frame
add(panel);
}
// main method to invoke the class
public static void main(String[] args) {
CAL cal = new CAL();
cal.setVisible(true);
cal.pack();
cal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
上面的程序首先声明了我们将在布局中使用的所有组件和字段。然后,它继续创建addComponent 帮助方法,将有约束的组件添加到面板上。
这个方法的insets,anchor, 和fill 在整个程序中保持不变。这是因为这些值在所有组件中都是一样的。如果这些值是不同的,请创建另一个方法,并将这些约束传递给该方法。
可以有不同的addComponent 方法,但有不同的签名。只有当组件有不同的约束条件时才这样做。构造函数以初始化超类构造函数(JFrame)开始。
super("Computer Assisted Learning");
传入的字符串是应用程序的标题。

然后它创建一个新的面板对象,并将面板的布局设置为 "GridBagLayout"。这就是我们设置面板布局的地方。布局可以是上面列出的任何布局,但为了本教程,我们将使用 "GridBagLayout"。
panel = new JPanel();
panel.setLayout(new GridBagLayout()); // set panel's layout
现在,接下来的一系列语句初始化了申报的组件,然后我们给这些组件添加了一些样式。然后我们继续使用前面定义的addComponent 方法将每个组件添加到面板上。它把要添加组件的面板、组件和约束条件作为一个参数。
add(panel, level, 0, 0, 1, 1);
add(panel, type, 2, 0, 1, 1);
add(panel, question, 0, 1, 3, 1);
add(panel, start, 0, 3, 1, 1);
add(panel, answer, 1, 2, 1, 1);
add(panel, stop, 2, 3, 1, 1);
add(panel, enter, 1, 3, 1, 1);
然后我们使用继承自JFrame的add方法,将我们的面板添加到框架中。
add(panel);
我们需要将所有定义的面板添加到框架中,以便查看组件。
// main method to invoke the class
public static void main(String[] args) {
CAL cal = new CAL();
cal.setVisible(true);
cal.pack();
cal.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
程序的主方法首先创建一个类的对象,然后调用一些方法。setVisible 设置应用程序窗口的可见性。pack 调整窗口以适应其子组件的大小。
setDefaultCloseOperation 收取一个操作,决定当用户点击窗口上的关闭图标时将发生什么。在这种情况下,JFrame.EXIT_ON_CLOSE 将停止该应用程序。

总结
在Java中构建GUI应用程序对开发者来说是一次有趣的冒险,因为用户可以与你的应用程序进行视觉上的互动。更重要的是要知道如何使用正确的工具来构建应用程序。
使用CAL来解释Gridbag布局的概念是为了显示这个概念的实现和重要性。