文档

Java™ 教程
隐藏目录
如何使用BoxLayout
指南: 使用 Swing 创建 GUI
课程: 在容器中布局组件

如何使用 BoxLayout


注意: 本课程介绍了手动编写布局代码,这可能具有挑战性。如果您对学习布局管理的所有细节不感兴趣,可以选择使用GroupLayout布局管理器与构建工具来布局您的GUI。其中一个构建工具是NetBeans IDE。否则,如果您想手动编写代码并且不想使用GroupLayout,那么建议使用GridBagLayout作为下一个最灵活和强大的布局管理器。

如果您有兴趣使用JavaFX创建GUI,请参阅JavaFX中的布局

Swing包中包含一个通用的布局管理器,名为BoxLayoutBoxLayout可以将其组件堆叠在一起或将它们放置在一行中,由您选择。您可以将其视为具有更多功能的FlowLayout版本。这是一个应用程序的图片,演示了使用BoxLayout来显示居中的组件列:

BoxLayoutDemo的快照

点击启动按钮以使用Java™ Web Start运行BoxLayoutDemo(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引

启动BoxLayoutDemo示例

您可以在BoxLayoutDemo.java中查看代码。

下图显示了一个使用两个BoxLayout实例的GUI。在GUI的顶部部分,一个从上到下的盒子布局将标签放置在滚动面板上方。在GUI的底部部分,一个从左到右的盒子布局将两个按钮放置在一起。一个BorderLayout将GUI的两个部分结合起来,并确保任何多余的空间都给予滚动面板。

同时使用从左到右和从上到下的盒子布局

您可以在使用Swing组件示例索引中找到运行ListDialog和其源文件的链接。

下面的代码取自ListDialog.java,布局了GUI。这段代码位于对话框的构造函数中,该构造函数被实现为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,将高度替换为宽度,依此类推。


版本说明: 在JDK 1.4版本之前,没有为以本地化方式指定盒式布局的轴线存在常量。相反,创建BoxLayout时,你需要指定X_AXIS(从左到右)或Y_AXIS(从上到下)。我们的示例现在使用了常量LINE_AXISPAGE_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对齐的三个组件

如你所见,具有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对齐方式(如居中)的组件将与其容器一样宽。这里有两个示例:

具有混合X对齐方式和无最大尺寸的三个组件具有混合X对齐方式和无最大尺寸的三个组件

为了更好地了解 BoxLayout ,您可以使用 BoxLayoutDemo2 运行自己的实验。


试试看: 
  1. 点击“Launch”按钮使用 Java™ Web Start 运行 BoxLayoutDemo2 (下载 JDK 7 或更高版本)。或者,如果想要编译并运行示例,请参考示例索引启动 BoxLayoutDemo2 示例

    您可以在 BoxLayoutDemo2.java 中看到代码。
    您将看到一个包含三个矩形的窗口。每个矩形都是 BLDComponent 的实例,它是 JComponent 的子类。

  2. 点击一个矩形的内部。
    这是更改矩形的X对齐方式的方法。
  3. 点击窗口底部的复选框。
    这将关闭所有矩形的限制大小。
  4. 将窗口调高。
    这将使矩形的容器大于矩形的首选大小之和。容器是一个带有红色轮廓的 JPanel ,以便您可以知道容器的边界在哪里。

使用不可见组件作为填充物

由箱式布局控制的每个组件都与其相邻的组件紧挨着。如果您希望组件之间有间隔,可以为一个或两个组件添加一个空的 边框 ,或者插入不可见的组件来提供间隔。您可以利用 Box 类创建不可见组件。

Box类定义了一个嵌套类Box.Filler,它是一个透明的组件,不绘制任何内容,用于提供其他组件之间的空间。然而,Filler实际上不是不可见的,因为没有调用setVisible(false)方法。Box类提供了方便的方法来帮助您创建常见类型的填充器。以下表格详细介绍了使用BoxBox.Filler创建不可见组件的方法。

类型 尺寸约束 创建方法
刚性区域 具有混合X对齐方式和没有最大尺寸的三个组件
Box.createRigidArea(size)
粘合剂,水平方向 具有混合X对齐方式和没有最大尺寸的三个组件
Box.createHorizontalGlue()
粘合剂,垂直方向 具有混合X对齐方式和没有最大尺寸的三个组件
Box.createVerticalGlue()
自定义Box.Filler (如指定) new Box.Filler(minSize, prefSize, maxSize)

以下是每种类型填充器的一般用法:

固定区域
当您希望两个组件之间有固定大小的间距时,请使用此功能。例如,在从左到右的盒式布局中,在两个组件之间放置5个像素的间距,您可以使用以下代码:
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
使用此选项指定具有所需的最小、首选和最大尺寸的组件。例如,在从左到右的布局中创建一些填充,在两个组件之间至少放置5个像素,并确保容器具有最小高度为100像素,您可以使用以下代码:
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控制的所有组件应具有相同的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或更高版本)。或者,要自己编译和运行示例,请参考示例索引

启动BoxAlignmentDemo示例

默认情况下,大多数组件都具有居中的X和Y对齐方式。但是,按钮、组合框、标签和菜单项具有不同的默认X对齐值:LEFT_ALIGNMENT。上图显示了如果将左对齐组件(如标签)与居中对齐组件放在由顶部到底部的BoxLayout控制的容器中会发生什么。

BoxAlignmentDemo程序提供了修复不匹配对齐问题的示例。通常情况下,只需将有问题的按钮或标签设置为居中对齐即可。例如:

label.setAlignmentX(Component.CENTER_ALIGNMENT);

指定组件大小

如前所述,BoxLayout会注意组件的最小、首选和最大大小。在调整布局时,您可能需要调整这些大小。

有时候,调整大小的需求是显而易见的。例如,按钮的最大大小通常与其首选大小相同。如果您希望按钮在有额外空间时绘制得更宽,那么您需要更改其最大大小。

然而,有时候需要调整大小的需求并不那么明显。您可能在使用箱式布局时得到了意外的结果,但可能不知道原因。在这种情况下,通常最好首先将问题视为对齐问题。如果调整对齐方式没有帮助,那么可能存在大小问题。稍后我们将进一步讨论这个问题。


注意: BoxLayout虽然会注意组件的最大大小,但许多布局管理器并不会。例如,如果将按钮放在BorderLayout的底部部分,不管按钮的最大大小是什么,该按钮的宽度可能都会超过其首选宽度。BoxLayout则从不使按钮的宽度超过其最大大小。

您可以通过以下两种方式更改最小、首选和最大大小:

如果使用箱式布局遇到问题,并且已经排除了对齐问题,那么问题很可能与大小相关。例如,如果由箱式布局控制的容器占用了太多空间,那么容器中的一个或多个组件可能需要限制其最大大小。

您可以使用两种技术来跟踪箱式布局中的大小问题:

BoxLayout API

下表列出了常用的BoxLayoutBox的构造函数和方法。使用盒式布局的API分为以下几个类别:

创建BoxLayout对象
构造函数或方法 目的
BoxLayout(Container, int) 创建一个控制指定ContainerBoxLayout实例。整数参数指定容器中组件布局的轴线。当容器具有默认的组件方向时,BoxLayout.LINE_AXIS指定组件从左到右布局,BoxLayout.PAGE_AXIS指定组件从上到下布局。
Box(int) 创建一个Box - 使用指定的轴线的BoxLayout的容器。
static Box createHorizontalBox()
(在Box中)
创建一个从左到右布局的Box
static Box createVerticalBox()
(在Box中)
创建一个从上到下布局的Box
创建占位符
这些方法在Box类中定义。
构造函数或方法 目的
Component createRigidArea(Dimension) 创建一个固定大小的组件。
Component createHorizontalGlue()
Component createVerticalGlue()
Component createGlue()
创建一个可拉伸的组件。水平和垂直的可拉伸组件非常有用。
Component createHorizontalStrut()
Component createVerticalStrut()
创建一个"支撑"组件。我们建议使用固定大小的组件代替支撑。
Box.Filler(Dimension, Dimension, Dimension) 创建一个具有指定最小、首选和最大大小的组件(按照给定顺序指定的参数)。有关详细信息,请参阅本节前面的自定义Box.Filler讨论。
其他有用的方法
方法 目的
void changeShape(Dimension, Dimension, Dimension) (在Box.Filler中) 更改接收者Box.Filler对象的最小、首选和最大尺寸。布局相应地更改。

使用Box布局的示例

以下表格列出了一些使用Box布局的示例。

示例 描述 备注
BoxLayoutDemo2 本页 使用盒子布局创建一个居中的组件列。
BoxAlignmentDemo 本页 演示如何解决常见的对齐问题。
BoxLayoutDemo 本页 允许您调整对齐和最大尺寸。
ListDialog 本页 使用从上到下的盒子布局和从左到右的盒子布局的一个简单而真实的示例。使用水平粘性、刚性区域和空边框。还设置了组件的X对齐方式。
InternalFrameEventDemo 如何编写内部框架监听器 使用从上到下的布局将按钮和滚动面板居中在内部框架中。
MenuGlueDemo 自定义菜单布局 演示如何使用粘合组件将菜单右对齐到菜单栏中。
MenuLayoutDemo 自定义菜单布局 演示如何通过将菜单栏更改为使用从上到下的盒子布局,上下文菜单使用从左到右的盒子布局来自定义菜单布局。
ConversionPanel.javaConverter示例中 如何使用面板 通过将组件的宽度设置为相同,并将它们的容器的宽度设置为相同,将两个组件在不同的盒子布局控制的容器中对齐。

上一页: 如何使用BorderLayout
下一页: 如何使用CardLayout