这些 Java 教程是针对 JDK 8 编写的。本页面描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关 Java SE 9 及后续版本中更新的语言功能的摘要,请参阅Java 语言更改。
有关所有 JDK 发行版的新功能、增强功能以及已删除或已弃用选项的信息,请参阅JDK 发行说明。
GroupLayout
布局管理器与构建工具来布局您的GUI。其中一个构建工具是NetBeans IDE。否则,如果您想手动编写代码并且不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用JavaFX创建GUI,请参阅JavaFX中的布局。
Swing包中包含一个通用的布局管理器,名为BoxLayout
。 BoxLayout
可以将其组件堆叠在一起或将它们放置在一行中,由您选择。您可以将其视为具有更多功能的FlowLayout
版本。这是一个应用程序的图片,演示了使用BoxLayout
来显示居中的组件列:
点击启动按钮以使用Java™ Web Start运行BoxLayoutDemo(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
您可以在BoxLayoutDemo.java
中查看代码。
下图显示了一个使用两个BoxLayout
实例的GUI。在GUI的顶部部分,一个从上到下的盒子布局将标签放置在滚动面板上方。在GUI的底部部分,一个从左到右的盒子布局将两个按钮放置在一起。一个BorderLayout
将GUI的两个部分结合起来,并确保任何多余的空间都给予滚动面板。
您可以在使用Swing组件示例索引中找到运行ListDialog和其源文件的链接。
下面的代码取自
,布局了GUI。这段代码位于对话框的构造函数中,该构造函数被实现为ListDialog.java
JDialog
子类。代码中加粗的行设置了框布局并向其中添加组件。
JScrollPane listScroller = new JScrollPane(list); listScroller.setPreferredSize(new Dimension(250, 80)); listScroller.setAlignmentX(LEFT_ALIGNMENT); ... //从上到下布局标签和滚动面板。 JPanel listPane = new JPanel(); listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS)); JLabel label = new JLabel(labelText); ... listPane.add(label); listPane.add(Box.createRigidArea(new Dimension(0,5))); listPane.add(listScroller); listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); //从左到右布局按钮。 JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(cancelButton); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); buttonPane.add(setButton); //使用内容面板的边界布局将所有内容组合在一起。 Container contentPane = getContentPane(); contentPane.add(listPane, BorderLayout.CENTER); contentPane.add(buttonPane, BorderLayout.PAGE_END);
第一个加粗的行创建了一个从上到下的框布局,并将其设置为listPane
的布局管理器。BoxLayout
构造函数的两个参数分别是要管理的容器和组件将被布局的轴线。常量PAGE_AXIS
指定组件应该按照目标容器的ComponentOrientation
属性决定的页面流动方向进行布局。常量LINE_AXIS
指定组件应该按照目标容器的ComponentOrientation
属性决定的文本行方向进行布局。这些常量允许进行国际化,通过使用正确的从左到右、从右到左或从上到下方向布局组件。
接下来的三行加粗的代码将标签和滚动面板添加到容器中,并使用刚性区域(一种不可见的组件,用于在组件之间添加空间)将它们分隔开。在这种情况下,刚性区域没有宽度,并且在标签和滚动面板之间精确地添加了5个像素的间距。刚性区域将在稍后的使用不可见组件作为填充物中进行讨论。
下一个粗体代码块创建了一个从左到右的盒式布局,并为buttonPane
容器设置了布局。然后,代码向容器中添加了两个按钮,使用了一个刚性区域在按钮之间放置了10像素的间距。为了将按钮放置在容器的右侧,首先添加到容器的组件是glue。这个glue是一个看不见的组件,根据需要可以自动增长来吸收其容器中的任何额外空间。关于glue的使用可以参考使用看不见的组件作为填充。
除了使用看不见的组件,有时候你也可以使用空边框来在组件周围创建间距,尤其是面板。例如,前面的代码片段使用空边框在对话框和其内容之间以及内容的两个部分之间放置了10像素的间距。边框与布局管理器完全独立。它们只是Swing组件绘制边缘并在组件内容和边缘之间提供填充的方式。详见如何使用边框获取更多信息。
下面的章节会更详细地讨论BoxLayout
:
不要因为BoxLayout
的讨论内容很长而感到害怕!你可能已经可以使用BoxLayout
了。如果遇到问题或者想要充分利用BoxLayout
的功能,请继续阅读。
如前所述,BoxLayout
要么将组件垂直排列,要么将组件水平排列。在布局组件时,它会考虑组件的对齐方式以及最小、首选和最大大小。在本节中,我们将讨论从上到下的布局。相同的概念也适用于从左到右或从右到左的布局。你只需要将X替换为Y,将高度替换为宽度,依此类推。
BoxLayout
时,你需要指定X_AXIS
(从左到右)或Y_AXIS
(从上到下)。我们的示例现在使用了常量LINE_AXIS
和PAGE_AXIS
,它们更受欢迎,因为它们能够适应具有不同方向的语言。在默认的从左到右布局中,LINE_AXIS
指定从左到右布局,PAGE_AXIS
指定从上到下布局。
当一个BoxLayout
从上到下布置组件时,它会尝试将每个组件的大小设置为组件的首选高度。如果布局的垂直空间与首选高度之和不匹配,则BoxLayout
会尝试调整组件的大小以填充空间。组件会根据空间的大小增长或缩小,同时BoxLayout
会考虑每个组件的最小和最大大小。任何额外的空间将出现在容器的底部。
对于从上到下的盒式布局,容器的首选宽度是子组件的最大首选宽度。如果容器被强制宽度大于此值,则BoxLayout
会尝试将每个组件的宽度设置为容器的宽度(减去插入)。如果组件的最大大小小于容器的宽度,则会使用X对齐。
X对齐不仅影响组件之间的位置,还影响组件(作为一组)在其容器中的位置。下图说明了具有受限制最大宽度的组件的对齐方式。
在第一个图中,所有三个组件的X对齐为0.0(Component.LEFT_ALIGNMENT
)。这意味着组件的左边应对齐。此外,它意味着所有三个组件在容器中的位置尽可能靠左。
在第二个图中,所有三个组件的X对齐为0.5(Component.CENTER_ALIGNMENT
)。这意味着组件的中心应对齐,并且组件应位于其容器的水平中心。
在第三个图中,组件的X对齐为1.0(Component.RIGHT_ALIGNMENT
)。你可以猜到这对于组件的对齐和相对于其容器的位置意味着什么。
你可能想知道当组件既有受限制的最大大小又具有不同的X对齐时会发生什么。下一个图显示了一个示例:
如你所见,具有X对齐为0.0(Component.LEFT_ALIGNMENT
)的组件的左边与具有X对齐为0.5(Component.CENTER_ALIGNMENT
)的组件的中心对齐,后者又与具有X对齐为1.0(Component.RIGHT_ALIGNMENT
)的组件的右边对齐。像这样的混合对齐问题在修复对齐问题中进一步讨论。
如果没有任何组件具有最大宽度,会发生什么情况?在这种情况下,如果所有组件具有相同的X对齐方式,则所有组件的宽度将与其容器一样宽。如果X对齐方式不同,则具有X对齐方式为0.0(左)或1.0(右)的任何组件将较小。所有具有中间X对齐方式(如居中)的组件将与其容器一样宽。这里有两个示例:
为了更好地了解 BoxLayout
,您可以使用 BoxLayoutDemo2 运行自己的实验。
您可以在 BoxLayoutDemo2.java
中看到代码。
您将看到一个包含三个矩形的窗口。每个矩形都是 BLDComponent
的实例,它是 JComponent
的子类。
JPanel
,以便您可以知道容器的边界在哪里。由箱式布局控制的每个组件都与其相邻的组件紧挨着。如果您希望组件之间有间隔,可以为一个或两个组件添加一个空的 边框 ,或者插入不可见的组件来提供间隔。您可以利用 Box
类创建不可见组件。
Box
类定义了一个嵌套类Box.Filler
,它是一个透明的组件,不绘制任何内容,用于提供其他组件之间的空间。然而,Filler
实际上不是不可见的,因为没有调用setVisible(false)
方法。Box
类提供了方便的方法来帮助您创建常见类型的填充器。以下表格详细介绍了使用Box
和Box.Filler
创建不可见组件的方法。
类型 | 尺寸约束 | 创建方法 |
---|---|---|
刚性区域 | Box.createRigidArea(size) |
|
粘合剂,水平方向 | Box.createHorizontalGlue() |
|
粘合剂,垂直方向 | Box.createVerticalGlue() |
|
自定义Box.Filler |
(如指定) | new Box.Filler(minSize, prefSize, maxSize) |
以下是每种类型填充器的一般用法:
container.add(firstComponent); container.add(Box.createRigidArea(new Dimension(5,0))); container.add(secondComponent);
注意:Box类还提供了另一种用于在组件之间放置固定空间的填充器:垂直或水平的strut。不幸的是,strut的最大高度或宽度是无限的(分别为水平和垂直strut)。这意味着如果在垂直盒式布局中使用水平盒式布局,水平盒式布局有时可能会变得过高。因此,我们建议使用固定区域而不是struts。
container.add(firstComponent); container.add(Box.createHorizontalGlue()); container.add(secondComponent);
Box.Filler
container.add(firstComponent); Dimension minSize = new Dimension(5, 100); Dimension prefSize = new Dimension(5, 100); Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); container.add(new Box.Filler(minSize, prefSize, maxSize)); container.add(secondComponent);
BoxLayout
有两种对齐问题:
BoxLayout
控制的两个或多个组件具有不同的默认对齐方式,导致它们无法对齐。例如,如下所示,如果一个标签和一个面板位于垂直布局中,标签的左边缘默认与面板的中心对齐。
一般来说,由顶部到底部的BoxLayout
控制的所有组件应具有相同的X对齐方式。类似地,由左到右的BoxLayout
控制的所有组件应具有相同的Y对齐方式。您可以通过调用setAlignmentX
方法来设置JComponent
的X对齐方式。对于所有组件,另一种可用的方法是在组件类的自定义子类中覆盖getAlignmentX
方法。类似地,您可以通过调用setAlignmentY
方法或覆盖getAlignmentY
方法来设置组件的Y对齐方式。
下面是一个示例,取自名为BoxAlignmentDemo
的应用程序,更改两个按钮的Y对齐方式,使按钮的底部对齐:
button1.setAlignmentY(Component.BOTTOM_ALIGNMENT); button2.setAlignmentY(Component.BOTTOM_ALIGNMENT);
单击“启动”按钮以使用Java™ Web Start运行BoxAlignmentDemo(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
默认情况下,大多数组件都具有居中的X和Y对齐方式。但是,按钮、组合框、标签和菜单项具有不同的默认X对齐值:LEFT_ALIGNMENT
。上图显示了如果将左对齐组件(如标签)与居中对齐组件放在由顶部到底部的BoxLayout
控制的容器中会发生什么。
BoxAlignmentDemo
程序提供了修复不匹配对齐问题的示例。通常情况下,只需将有问题的按钮或标签设置为居中对齐即可。例如:
label.setAlignmentX(Component.CENTER_ALIGNMENT);
如前所述,BoxLayout
会注意组件的最小、首选和最大大小。在调整布局时,您可能需要调整这些大小。
有时候,调整大小的需求是显而易见的。例如,按钮的最大大小通常与其首选大小相同。如果您希望按钮在有额外空间时绘制得更宽,那么您需要更改其最大大小。
然而,有时候需要调整大小的需求并不那么明显。您可能在使用箱式布局时得到了意外的结果,但可能不知道原因。在这种情况下,通常最好首先将问题视为对齐问题。如果调整对齐方式没有帮助,那么可能存在大小问题。稍后我们将进一步讨论这个问题。
BoxLayout
虽然会注意组件的最大大小,但许多布局管理器并不会。例如,如果将按钮放在BorderLayout
的底部部分,不管按钮的最大大小是什么,该按钮的宽度可能都会超过其首选宽度。BoxLayout
则从不使按钮的宽度超过其最大大小。
您可以通过以下两种方式更改最小、首选和最大大小:
setXxxSize
方法(由JComponent
类定义)。例如:
comp.setMinimumSize(new Dimension(50, 25)); comp.setPreferredSize(new Dimension(50, 25)); comp.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
getXxxSize
方法。例如:
...//在组件类的子类中: public Dimension getMaximumSize() { size = getPreferredSize(); size.width = Short.MAX_VALUE; return size; }
如果使用箱式布局遇到问题,并且已经排除了对齐问题,那么问题很可能与大小相关。例如,如果由箱式布局控制的容器占用了太多空间,那么容器中的一个或多个组件可能需要限制其最大大小。
您可以使用两种技术来跟踪箱式布局中的大小问题:
comp.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(Color.red), comp.getBorder()));
System.out.println
打印组件的最小、首选和最大大小,以及可能的边界。下表列出了常用的BoxLayout
和Box
的构造函数和方法。使用盒式布局的API分为以下几个类别:
构造函数或方法 | 目的 |
---|---|
BoxLayout(Container, int) |
创建一个控制指定Container 的BoxLayout 实例。整数参数指定容器中组件布局的轴线。当容器具有默认的组件方向时,BoxLayout.LINE_AXIS 指定组件从左到右布局,BoxLayout.PAGE_AXIS 指定组件从上到下布局。 |
Box(int) |
创建一个Box - 使用指定的轴线的BoxLayout 的容器。 |
static Box createHorizontalBox() (在 Box 中) |
创建一个从左到右布局的Box 。 |
static Box createVerticalBox() (在 Box 中) |
创建一个从上到下布局的Box 。 |
构造函数或方法 | 目的 |
---|---|
Component createRigidArea(Dimension) |
创建一个固定大小的组件。 |
Component createHorizontalGlue() |
创建一个可拉伸的组件。水平和垂直的可拉伸组件非常有用。 |
Component createHorizontalStrut() |
创建一个"支撑"组件。我们建议使用固定大小的组件代替支撑。 |
Box.Filler(Dimension, Dimension, Dimension) |
创建一个具有指定最小、首选和最大大小的组件(按照给定顺序指定的参数)。有关详细信息,请参阅本节前面的自定义Box.Filler 讨论。 |
方法 | 目的 |
---|---|
void changeShape(Dimension, Dimension, Dimension) (在Box.Filler 中) |
更改接收者Box.Filler 对象的最小、首选和最大尺寸。布局相应地更改。 |
以下表格列出了一些使用Box布局的示例。
示例 | 描述 | 备注 |
---|---|---|
BoxLayoutDemo2 | 本页 | 使用盒子布局创建一个居中的组件列。 |
BoxAlignmentDemo | 本页 | 演示如何解决常见的对齐问题。 |
BoxLayoutDemo | 本页 | 允许您调整对齐和最大尺寸。 |
ListDialog | 本页 | 使用从上到下的盒子布局和从左到右的盒子布局的一个简单而真实的示例。使用水平粘性、刚性区域和空边框。还设置了组件的X对齐方式。 |
InternalFrameEventDemo | 如何编写内部框架监听器 | 使用从上到下的布局将按钮和滚动面板居中在内部框架中。 |
MenuGlueDemo | 自定义菜单布局 | 演示如何使用粘合组件将菜单右对齐到菜单栏中。 |
MenuLayoutDemo | 自定义菜单布局 | 演示如何通过将菜单栏更改为使用从上到下的盒子布局,上下文菜单使用从左到右的盒子布局来自定义菜单布局。 |
ConversionPanel.java 在Converter示例中 |
如何使用面板 | 通过将组件的宽度设置为相同,并将它们的容器的宽度设置为相同,将两个组件在不同的盒子布局控制的容器中对齐。 |