11.3.4 GridBagLayout布局管理器

11.3.4 GridBagLayout布局管理器

GridBagLayout布局管理器的功能最强大,但也最复杂。

GridBagLayoutGridLayout布局管理器的不同

GridLayout布局管理器不同的是,GridBagLayout布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同,从而增加了布局的灵活性。当窗口的大小发生变化时,GridLayout布局管理器也可以准确地控制窗口各部分的拉伸。

为了处理GridLayoutGUI组件的大小、跨越性,Java提供了GridBagConstraints对象,该对象与特定的GUI组件关联,用于控制该GUI组件的大小、跨越性。

使用GridBagLayout布局管理器的步骤

使用GridBagLayout布局管理器的步骤如下:

  1. 创建GridBagLayout布局管理器,并指定GUI容器使用该布局管理器:
    1
    2
    GridBagLayout gb = new GridBagLayout();
    container.setLayout(gb);
  2. 创建GridBagConstraints对象,并设置该对象的相关属性(用于设置受该对象控制的GUI组件的大小、跨越性等)。
    1
    2
    3
    4
    gbc.grid=2;       //设置受该对象控制的GUI组件位于网格的横向索引
    gbc.grid=1; //设置受该对象控制的GUI组件位于网格的纵向索引
    gbc.gridwidth=2; //设置受该对象控制的GUI组件横向跨越多少网格
    gbc.gridheight=1; //设置受该对象控制的GUI组件纵向跨越多少网格
  3. 调用GridBagLayout对象的方法来建立GridBagConstraints对象和受控制组件之间的关联
    1
    gb.setConstraints(c,gbc);//设置c组件受gbc对象控制
  4. 添加组件,与采用普通布局管理器添加组件的方法完全一样:
    1
    container.add(c);

如果需要向一个容器中添加多个GUI组件,则需要多次重复步骤2~4。由于GridBagConstraints对象可以多次重用,所以实际上只需要创建一个GridBagConstraints对象,每次添加GUI组件之前先改变GridBagConstraints对象的属性即可

从上面介绍中可以看出,使用GridBagLayout布局管理器的关键在于GridBagConstraints,它才是精确控制每个GUI组件的核心类,该类具有如下几个属性。

  • gridxgridy
    • 设置受该对象控制的GUI组件左上角所在网格的横向索引、纵向索引(GridLayout左上角网格的索引为0、0)。这两个值还可以是GridBagConstraints.RELATIVE(默认值),它表明当前组件紧跟在上一个组件之后。
  • gridheightgridwidth:
    • 设置受该对象控制的GUI组件横向、纵向跨越多少个网格,两个属性值的默认值都是1。
    • 如果设置这两个属性值为:GridBagConstraints.REMANDER,这表明受该对象控制的GUI组件是横向、纵向最后一个组件;
    • 如果设置这两个属性值为:GridBagConstraints.RELATIVE,这表明受该对象控制的GUI组件是横向、纵向倒数第二个组件。
  • fill:
    • 设置受该对象控制的GUI组件如何占据空白区域。该属性的取值如下
    • GridBagConstraints.NONEGUI组件不扩大
    • GridBagConstraints.HORIZONTALGUI组件水平扩大以占据空白区域
    • GridBagConstraints.VERTICALGUI组件垂直扩大以占据空白区域。
    • GridBagConstraints.BOTHGUI件水平、垂直同时扩大以占据空白区域
  • ipadxipady:设置受该对象控制的GUI组件横向、纵向内部填充的大小,即在该组件最小尺寸的基础上还需要增大多少。如果设置了这两个属性,则组件横向大小为最小宽度再加ipade*2像素,纵向大小为最小高度再加ipad*2像素。
  • insets:设置受该对象控制的GUI组件的外部填充的大小,即该组件边界和显示区域边界之间的距离。
  • anchor:设置受该对象控制的GUI组件在其显示区域中的定位方式。定位方式如下
    • GridBagConstraints.CENTER(中间)
    • GridBagConstraints.NORTH(上中)
    • GridBagConstraints.NORTHWEST(左上角)
    • GridBagConstraints.NORTHEAST(右上角)
    • GridBagConstraints.SOUTH(下中)
    • GridBagConstraints.SOUTHEAST(右下角)
    • GridBagConstraints.SOUTHWEST(左下角)
    • GridBagConstraints.EAST(右中)
    • GridBagConstraints.WEST(左中)
  • weightweighty:设置受该对象控制的GUI组件占据多余空间的水平、垂直增加比例(也叫权重,即weight的直译),这两个属性的默认值是0,即该组件不占据多余空间。假设某个容器的水平线上包括三个GUI组件,它们的水平增加比例分别是1、2、3,但容器宽度增加60像素时,则第一个组件宽度增加10像素,第二个组件宽度增加20像素,第三个组件宽度增加30像素。如果其增加比例为0,则表示不会增加。

设置某个组件随容器的增大而增大

如果希望某个组件的大小随容器的増大而増大,则必须同时设置控制该组件GridBagConstraints对象的fill属性和weightweighty属性。

程序示例

下面的例子程序示范了如何使用GridBagLayout布局管理器来管理窗口中的10个按钮:

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
import java.awt.*;

public class GridBagTest {
private Frame f = new Frame("测试窗口");
private GridBagLayout gb = new GridBagLayout();
private GridBagConstraints gbc = new GridBagConstraints();
private Button[] bs = new Button[10];

public void init() {
f.setLayout(gb);
for (int i = 0; i < bs.length; i++) {
bs[i] = new Button("按钮" + i);
}
// 所有组件都可以横向、纵向上扩大
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
addButton(bs[0]);
addButton(bs[1]);
addButton(bs[2]);
// 该GridBagConstraints控制的GUI组件将会成为横向最后一个元素
gbc.gridwidth = GridBagConstraints.REMAINDER;
addButton(bs[3]);
// 该GridBagConstraints控制的GUI组件将横向上不会扩大
gbc.weightx = 0;
addButton(bs[4]);
// 该GridBagConstraints控制的GUI组件将横跨两个网格
gbc.gridwidth = 2;
addButton(bs[5]);
// 该GridBagConstraints控制的GUI组件将横跨一个网格
gbc.gridwidth = 1;
// 该GridBagConstraints控制的GUI组件将纵向跨两个网格
gbc.gridheight = 2;
// 该GridBagConstraints控制的GUI组件将会成为横向最后一个元素
gbc.gridwidth = GridBagConstraints.REMAINDER;
addButton(bs[6]);
// 该GridBagConstraints控制的GUI组件将横向跨越一个网格,纵向跨越2个网格。
gbc.gridwidth = 1;
gbc.gridheight = 2;
// 该GridBagConstraints控制的GUI组件纵向扩大的权重是1
gbc.weighty = 1;
addButton(bs[7]);
// 设置下面的按钮在纵向上不会扩大
gbc.weighty = 0;
// 该GridBagConstraints控制的GUI组件将会成为横向最后一个元素
gbc.gridwidth = GridBagConstraints.REMAINDER;
// 该GridBagConstraints控制的GUI组件将纵向上横跨一个网格
gbc.gridheight = 1;
addButton(bs[8]);
addButton(bs[9]);
f.pack();
f.setVisible(true);
}

private void addButton(Button button) {
gb.setConstraints(button, gbc);
f.add(button);
}

public static void main(String[] args) {
new GridBagTest().init();
}
}

运行上面程序,会看到如图11.12所示的窗口。

图11.12

从图11.12中可以看出,虽然设置了按钮4、按钮5横向上不会扩大,但因为按钮4、按钮5的宽度会受上一行4个按钮的影响,所以它们实际上依然会变大;同理,虽然设置了按钮8、按钮9纵向上不会扩大,但因为受按钮7的影响,所以按钮9纵向上依然会变大(但按钮8不会变高)。

推荐使用init方法完成界面的初始化工作

上面程序把需要重复访问的AWT组件设置成成员变量,然后使用init()方法来完成界面的初始化工作,这种做法比前面那种在main方法里把AWT组件定义成局部变量的方式更好。