本教程针对JDK 8编写。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关Java SE 9及后续版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息,请参阅JDK发行说明。
GroupLayout
布局管理器结合构建工具来布局你的GUI。其中一个构建工具是NetBeans IDE。否则,如果你想手写代码而不想使用GroupLayout
,那么GridBagLayout
作为下一个最灵活和强大的布局管理器是推荐的。
如果你对使用JavaFX创建GUI感兴趣,请参阅JavaFX中的布局。
这是一个使用GridBagLayout
的示例图片。
点击“启动”按钮使用Java™ Web Start来运行GridBagLayoutDemo(下载JDK 7或更高版本)。或者,如果要编译和运行示例,请参考示例索引。
GridBagDemo的代码位于GridBagLayoutDemo.java
中。
GridBagLayout
是Java平台提供的最灵活和复杂的布局管理器之一。它将组件放置在一个由行和列组成的网格中,允许指定的组件跨越多个行或列。并非所有的行高度都相同,同样的,并非所有的列宽度都相同。基本上,GridBagLayout
将组件放置在一个网格的矩形(单元格)中,然后使用组件的首选大小来确定单元格的大小。
下图显示了上述小程序的网格。可以看到,网格有三行三列。第二行的按钮跨越了所有的列;第三行的按钮跨越了右边的两列。
如果您放大窗口,如下图所示,您将注意到底部行(包含Button 5)获得了所有新的垂直空间。新的水平空间均匀分配给所有列。这种调整大小行为是基于程序对GridBagLayout
中的各个组件分配的权重。您还会注意到,每个组件占用所有可用的水平空间 - 但不占用(如您在按钮5中所看到的那样)所有可用的垂直空间。这种行为也由程序指定。
程序指定其组件的大小和位置特性的方式是为每个组件指定约束。设置组件约束的首选方法是使用Container.add
变体,传递一个GridBagConstraints
对象,如下面的示例所示。
下面的章节解释了您可以设置的约束,并提供了示例。
以下代码是使用GridBagLayout
的容器中典型的代码。在下一节中,您将看到一个更详细的示例。
JPanel pane = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); //对于要添加到此容器的每个组件: //...创建组件... //...在GridBagConstraints实例中设置实例变量... pane.add(theComponent, c);
您可能已经从上面的示例中猜到,即使组件具有不同的约束,也可以重用相同的GridBagConstraints
实例。然而,建议您不要重用GridBagConstraints
,因为如果您忘记为每个新实例重置字段,这很容易引入微妙的错误。
GridBagLayout
控制具有从左到右的组件方向的容器。
您可以设置以下GridBagConstraints
实例变量:
gridx
, gridy
gridx=0
,最上面的行的地址为gridy=0
。使用GridBagConstraints.RELATIVE
(默认值)指定该组件放置在刚在该组件之前添加到容器中的组件的右侧(对于gridx
)或下方(对于gridy
)。我们建议为每个组件指定gridx
和gridy
值,而不仅仅使用GridBagConstraints.RELATIVE
;这样可以得到更可预测的布局。
gridwidth
, gridheight
gridwidth
)或行数(对于gridheight
)。这些约束条件指定组件使用的单元格数量,而不是像素数量。默认值为1。使用GridBagConstraints.REMAINDER
指定该组件为其所在行(对于gridwidth
)或列(对于gridheight
)中的最后一个组件。使用GridBagConstraints.RELATIVE
指定该组件为其所在行(对于gridwidth
)或列(对于gridheight
)中的倒数第二个组件。我们建议为每个组件指定gridwidth
和gridheight
值,而不仅仅使用GridBagConstraints.RELATIVE
和GridBagConstraints.REMAINDER
;这样可以得到更可预测的布局。
注意:GridBagLayout
不允许组件跨越多行,除非组件位于最左边的列,或者您为组件指定了正数gridx
和gridy
值。
fill
GridBagConstraints
常量)包括NONE
(默认值),HORIZONTAL
(使组件足够宽以水平填充其显示区域,但不更改其高度),VERTICAL
(使组件足够高以垂直填充其显示区域,但不更改其宽度),BOTH
(使组件完全填充其显示区域)。
ipadx
, ipady
ipadx*2
像素,因为填充适用于组件的两侧。类似地,组件的高度至少为其最小高度加上ipady*2
像素。
insets
Insets
对象的形式指定。默认情况下,每个组件都没有外部填充。
anchor
GridBagConstraints
常量)为CENTER
(默认值)、PAGE_START
、PAGE_END
、LINE_START
、LINE_END
、FIRST_LINE_START
、FIRST_LINE_END
、LAST_LINE_END
和LAST_LINE_START
。
下面是在具有默认从左到右的组件方向的容器中解释这些值的图片。
FIRST_LINE_START | PAGE_START | FIRST_LINE_END |
LINE_START | CENTER | LINE_END |
LAST_LINE_START | PAGE_END | LAST_LINE_END |
PAGE_*
和*LINE_*
常量在1.4版本中引入。之前的版本需要按照罗盘方位命名的值。例如,NORTHEAST
表示显示区域的右上部分。我们建议您使用新的常量,因为它们更易于本地化。
weightx
, weighty
GridBagLayout
控制的组件外观产生重要影响的技巧。权重用于确定如何在列(weightx
)和行(weighty
)之间分配空间;这对于指定调整大小的行为非常重要。
除非您至少为weightx
或weighty
指定一个非零值,否则所有组件都会集中在容器的中心。这是因为当权重为0.0(默认值)时,GridBagLayout
将任何额外的空间放置在其单元格网格和容器边缘之间。
通常情况下,权重以0.0和1.0作为极端值:在中间的数字根据需要使用。较大的数字表示组件的行或列应该获得更多的空间。对于每一列,权重与该列内指定的组件的最高weightx
相关联,每个多列组件的权重在其所在的列之间进行分割。类似地,每一行的权重与该行内指定的组件的最高weighty
相关联。额外的空间倾向于向右下角的列和底部行。
下一部分在解释示例程序的工作原理的背景下详细讨论了约束。
这里再次展示了GridBagLayoutDemo应用程序的图片。
点击“启动”按钮使用Java™ Web Start运行GridBagLayoutDemo(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
下面的代码创建了GridBagLayout
和它管理的组件。你可以在GridBagLayoutDemo.java
中找到完整的源文件。
JButton button; pane.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); if (shouldFill) { //natural height, maximum width c.fill = GridBagConstraints.HORIZONTAL; } button = new JButton("按钮1"); if (shouldWeightX) { c.weightx = 0.5; } c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; pane.add(button, c); button = new JButton("按钮2"); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.5; c.gridx = 1; c.gridy = 0; pane.add(button, c); button = new JButton("按钮3"); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = 0.5; c.gridx = 2; c.gridy = 0; pane.add(button, c); button = new JButton("长名称按钮4"); c.fill = GridBagConstraints.HORIZONTAL; c.ipady = 40; //使该组件变高 c.weightx = 0.0; c.gridwidth = 3; c.gridx = 0; c.gridy = 1; pane.add(button, c); button = new JButton("5"); c.fill = GridBagConstraints.HORIZONTAL; c.ipady = 0; //重置为默认值 c.weighty = 1.0; //请求额外的垂直空间 c.anchor = GridBagConstraints.PAGE_END; //底部对齐 c.insets = new Insets(10,0,0,0); //顶部填充 c.gridx = 1; //与按钮2对齐 c.gridwidth = 2; //跨2列 c.gridy = 2; //第三行 pane.add(button, c);
该示例使用一个GridBagConstraints
实例来管理GridBagLayout
的所有组件,然而在实际情况中,建议不要重用GridBagConstraints
,因为如果你忘记为每个新实例重置字段,很容易引入细微的错误。在将每个组件添加到容器之前,代码会设置(或重置为默认值)GridBagConstraints
对象中的适当实例变量。然后,它将组件添加到其容器,将GridBagConstraints
对象作为add
方法的第二个参数指定。
例如,要使按钮4变得特别高,示例代码如下:
c.ipady = 40;
在设置下一个组件的约束之前,代码将ipady
的值重置为默认值:
c.ipady = 0;
如果组件的显示区域大于组件本身,则可以使用GridBagConstraints.anchor
约束指定组件在显示区域中的显示位置。 anchor
约束的值可以是绝对值(北,南,东,西等),或者是相对于方向的值(在页面开始,行末尾,第一行开始等),或者相对于组件基线的值。有关anchor
约束的所有可能值的完整列表,包括相对于基线的值,请参阅GridBagConstraints.anchor
的API文档。从上面的代码片段中可以看出,按钮5指定应该在显示区域的末尾显示,通过将锚点设置为GridBagConstraints.PAGE_END
。
GridBagLayout
对象上的setConstraints
方法来指定约束。例如:
GridBagLayout gridbag = new GridBagLayout(); pane.setLayout(gridbag); ... gridbag.setConstraints(button, c); pane.add(button);
Container.add
方法,因为它比使用setConstraints
更加简洁。
下表显示了GridBagLayoutDemo内容窗格中每个组件的所有约束条件。不是默认值的值用粗体标记。与上一个表项不同的值用斜体标记。
组件 | 约束条件 |
---|---|
所有组件 |
ipadx = 0 fill = GridBagConstraints.HORIZONTAL |
按钮1 |
ipady = 0 weightx = 0.5 weighty = 0.0 gridwidth = 1 anchor = GridBagConstraints.CENTER insets = new Insets(0,0,0,0) gridx = 0 gridy = 0 |
按钮2 |
weightx = 0.5 gridx = 1 gridy = 0 |
按钮3 |
weightx = 0.5 gridx = 2 gridy = 0 |
按钮4 |
ipady = 40 weightx = 0.0 gridwidth = 3 gridx = 0 gridy = 1 |
按钮5 |
ipady = 0 weightx = 0.0 weighty = 1.0 anchor = GridBagConstraints.PAGE_END insets = new Insets(10,0,0,0) gridwidth = 2 gridx = 1 gridy = 2 |
GridBagLayoutDemo有两个跨越多个列的组件(按钮4和按钮5)。为了使按钮4高,我们给它添加了内部填充(ipady
)。为了在按钮4和按钮5之间添加空间,我们使用插入值在按钮5上方添加了最小10个像素,并且让按钮5贴紧其单元格的底部边缘。
pane
容器中的所有组件都尽可能宽,给定它们所占用的单元格。程序通过将GridBagConstraints
的fill
实例变量设置为GridBagConstraints.HORIZONTAL
来实现这一点,并在所有组件上保持该设置。如果程序没有指定填充,则按钮的宽度将是其自然宽度,如下所示:
当你放大GridBagLayoutDemo的窗口时,列会按比例增长。这是因为第一行中的每个组件(每个组件为一列宽度)的weightx = 0.5
。这些组件的weightx
的实际值并不重要,重要的是所有的组件,因此所有的列都具有相等且大于0的权重。如果没有由GridBagLayout
管理的组件设置了weightx
,那么当容器的宽度增加时,组件将保持在容器的中心位置,如下所示:
如果容器的大小小于或大于首选大小,那么任何空间都会根据GridBagContainer
的权重进行分配。
请注意,如果您放大窗口,只有最后一行会变得更高。这是因为只有按钮5的weighty
大于零。
GridBagLayout
和GridBagConstraints
类只有一个构造函数,没有参数。您可以通过操作其实例变量来操纵GridBagConstraints
对象,如指定约束中所述。通常,在GridBagLayout
对象上只调用setConstraints
方法,如解释示例中所示。
在本教程中,您可以找到使用GridBagLayout
的示例。以下表格列出了一些示例。
示例 | 描述位置 | 备注 |
---|---|---|
GridBagLayoutDemo |
本节 | 使用了许多特性 - 权重、内边距、内部填充、水平填充、精确单元格定位、多列单元格和锚定(组件在单元格内的定位)。 |
TextSamplerDemo |
使用文本组件 | 对齐两组标签和文本字段,并在容器的整个宽度上添加一个标签。 |
ContainerEventDemo |
如何编写容器监听器 | 使用权重、填充和相对定位在容器内部放置五个组件。 |