文档

Java™ 教程
隐藏目录
使用布局管理器
教程:使用Swing创建GUI
课程:在容器中布局组件

使用布局管理器

布局管理器是实现了LayoutManager接口的对象,它确定容器内组件的大小和位置。虽然组件可以提供大小和对齐的提示,但容器的布局管理器决定组件在容器内的大小和位置。


注意: 本课程涵盖了手动编写布局代码的内容,这可能会有一定难度。如果你不想学习布局管理的所有细节,你可以选择使用GroupLayout布局管理器结合构建工具来布局你的GUI。其中一个这样的构建工具是NetBeans IDE。否则,如果你想手动编码而且不想使用GroupLayout,那么GridBagLayout作为下一个最灵活和强大的布局管理器是推荐的。

如果你想使用JavaFX来创建GUI,请参阅JavaFX中的布局

本节讨论了使用布局管理器相关的一些常见任务:

设置布局管理器

通常情况下,你只需要关注JPanel和内容面板content panes的布局管理器。每个JPanel对象在创建时会初始化为使用FlowLayout,除非在创建JPanel时另有指定。内容面板默认使用BorderLayout。如果你不喜欢面板或内容面板使用的默认布局管理器,你可以自由地将其更改为其他布局管理器。然而,除非你使用JToolBar,否则FlowLayoutBorderLayout布局管理器只适用于原型设计。任何真实的应用程序都需要重新设置布局管理器。同样,你应该使用适当的工具来完成这项任务,而不是手动编写管理器。

你可以使用JPanel构造函数设置面板的布局管理器。例如:

JPanel panel = new JPanel(new BorderLayout());

在创建容器后,你可以使用setLayout方法设置其布局管理器。例如:

Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());

虽然我们强烈建议使用布局管理器,但您也可以在没有布局管理器的情况下进行布局。通过将容器的布局属性设置为null,可以使容器不使用布局管理器。使用这种称为绝对定位的策略,您必须指定容器内每个组件的大小和位置。绝对定位的一个缺点是它在调整顶层容器大小时不会很好地调整。它也无法很好地适应用户和系统之间的差异,例如不同的字体大小和语言环境

向容器添加组件

当您将组件添加到面板或内容窗格时,您在add方法中指定的参数取决于面板或内容窗格使用的布局管理器。实际上,有些布局管理器甚至不需要您显式地添加组件;例如GroupLayout。例如,BorderLayout要求您使用类似下面的代码指定组件应添加到的区域(使用BorderLayout中定义的常量之一):

pane.add(aComponent, BorderLayout.PAGE_START);

每个布局管理器的“如何使用”部分都详细说明了您需要在add方法中指定的参数。某些布局管理器(例如GridBagLayoutSpringLayout)需要复杂的设置过程。然而,许多布局管理器只是根据它们添加到容器的顺序来放置组件。

除了JPanel和内容窗格之外,Swing容器通常提供应使用而不是add方法的API。例如,您可以在直接添加到滚动窗格(或者实际上添加到其视口)而不是在JScrollPane构造函数中指定组件,或者使用setViewportView。由于有了这样的专用API,您不需要知道许多Swing容器使用的布局管理器(如果有的话)。 (对于好奇的人:滚动窗格恰好使用名为ScrollPaneLayout的布局管理器。)

有关如何向特定容器添加组件的信息,请参阅容器的相关页面。您可以使用如何使用各种组件找到组件的相关页面。

提供大小和对齐提示

有时,您需要自定义组件向其容器的布局管理器提供的大小提示,以便组件能够良好地布局。您可以通过指定组件的最小、首选和最大尺寸之一或多个来实现这一点。您可以调用组件的设置大小提示的方法 - setMinimumSizesetPreferredSizesetMaximumSize。或者您可以创建一个子类,覆盖适当的getter方法 - getMinimumSizegetPreferredSizegetMaximumSize。以下是一个使组件的最大尺寸无限制的示例:

component.setMaximumSize(new Dimension(Integer.MAX_VALUE,
                                       Integer.MAX_VALUE));

许多布局管理器不会考虑组件的最大尺寸请求。然而,BoxLayoutSpringLayout会考虑。此外,GroupLayout提供了在不影响组件的情况下显式设置最小、首选或最大尺寸的能力。

除了提供尺寸提示外,您还可以提供对齐提示。例如,您可以指定两个组件的顶部边缘对齐。您可以通过调用组件的setAlignmentXsetAlignmentY方法或覆盖组件的getAlignmentXgetAlignmentY方法来设置对齐提示。尽管大多数布局管理器忽略对齐提示,但BoxLayout会将其作为参考。您可以在如何使用BoxLayout中找到设置对齐的示例。

在组件之间添加空间

容器中可见组件之间的间距受到以下三个因素的影响:

布局管理器
一些布局管理器会自动在组件之间添加间距,而其他布局管理器则不会。有些布局管理器允许您指定组件之间的间距大小。请参考每个布局管理器的相关页面了解有关间距支持的信息。
不可见组件
您可以创建轻量级组件,它们不进行绘制,但会在GUI中占据空间。通常,您会在由BoxLayout控制的容器中使用不可见组件。请参考如何使用BoxLayout,了解使用不可见组件的示例。
空边框
无论使用哪个布局管理器,您都可以通过向组件添加空边框来影响组件之间的间距。最适合空边框的候选组件是通常没有默认边框的面板和标签等组件。其他一些组件在某些外观实现中可能无法很好地使用边框,因为它们的绘制代码的实现方式不同。有关边框的信息,请参见如何使用边框

设置容器的方向

本网站使用英语编写,文本从左到右,然后从上到下。然而,许多其他语言具有不同的方向。 componentOrientation属性提供了一种指示特定组件应使用与默认的从左到右、从上到下方向不同的方向的方式。在像单选按钮这样的组件中,方向可能被用作提示,表示外观应该在按钮中切换图标和文本的位置。在容器中,方向被用作布局管理器的提示。

要设置容器的方向,您可以使用Component定义的setComponentOrientation方法,或者为了设置容器的子组件的方向,可以使用applyComponentOrientation方法。这两个方法的参数可以是常量,如ComponentOrientation.RIGHT_TO_LEFT,也可以是调用ComponentOrientation方法getOrientation(Locale)的结果。例如,以下代码会使所有的JComponent都使用阿拉伯语环境进行初始化,并相应地设置内容面板和其中的所有组件的方向:

JComponent.setDefaultLocale(new Locale("ar"));
JFrame frame = new JFrame();
...
Container contentPane = frame.getContentPane();
contentPane.applyComponentOrientation(
    ComponentOrientation.getOrientation(
        contentPane.getLocale()));

下面的两张图片展示了FlowLayout在方向完全相同但是容器不同的情况下如何布局组件。

FlowLayoutDemo默认从左到右的方向
默认方向(从左到右)

FlowLayoutDemo从右到左的方向
从右到左的方向

支持组件方向的标准布局管理器包括FlowLayoutBorderLayoutBoxLayoutGridBagLayoutGridLayout


注意: 必须注意将组件方向应用于渲染器、编辑器和通过容器层次结构的正常遍历无法访问的任何其他组件。

选择布局管理器的建议

布局管理器具有不同的优势和劣势。本节讨论了一些常见的布局场景以及每种布局管理器适用的场景。然而,再次强烈建议您使用构建工具来创建布局管理器,例如NetBeans IDE Matisse GUI builder,而不是手动编码管理器。下面列出的场景仅供参考,以了解在不同情况下使用哪种类型的管理器,或者如果您绝对必须手动编码管理器。

如果我们讨论的布局管理器都不适合您的情况,而且您不能使用构建工具,可以自由地使用您编写或找到的其他布局管理器。还要记住,像GridBagLayoutSpringLayout这样的灵活布局管理器可以满足许多布局需求。

场景:您需要在尽可能多的空间中显示一个组件。
如果它是容器中唯一的组件,请使用GridLayoutBorderLayout。否则,BorderLayoutGridBagLayout可能是一个很好的选择。

如果使用BorderLayout,您需要将占用空间较大的组件放在中心位置。如果使用GridBagLayout,您需要为组件设置约束条件,使fill=GridBagConstraints.BOTH。另一种可能性是使用BoxLayout,使占用空间较大的组件指定非常大的首选大小和最大大小。

场景:您需要以紧凑的行显示几个组件,其大小为其自然大小。
考虑使用JPanel来分组组件,并使用JPanel的默认FlowLayout管理器或BoxLayout管理器。对于这种情况,SpringLayout也很适合。
场景:您需要以行和列的方式显示几个相同大小的组件。
GridLayout非常适合这种情况。
场景:您需要以行或列的方式显示几个组件,可能在它们之间有不同的间距,自定义对齐方式或自定义组件大小。
BoxLayout非常适合这种情况。
场景:您需要显示对齐的列,就像在类似表单的界面中,使用一列标签来描述相邻列中的文本字段。
SpringLayout对此是一个很自然的选择。几个教程示例使用的SpringUtilities类定义了一个makeCompactGrid方法,可让您轻松地对齐多行多列的组件。
场景:您的布局很复杂,有许多组件。
考虑使用非常灵活的布局管理器,如GridBagLayoutSpringLayout,或将组件分组到一个或多个JPanel中以简化布局。如果采用后一种方法,每个JPanel可能使用不同的布局管理器。

第三方布局管理器

Java平台提供的布局管理器已经得到了Swing社区的补充,创建了其他第三方布局管理器。以下列表并非绝对,但下面列出的布局管理器是最受欢迎的:


*在JDK 1.1时代引入了第二个接口LayoutManager2LayoutManager2扩展了LayoutManager,提供了最大尺寸和对齐的支持。 LayoutManager2还添加了addLayoutComponent方法,它接受一个Object参数,并且有一个invalidateLayout方法。布局管理器还需要LayoutManager2提供的通知,因此任何现代布局管理器都需要实现它。


上一页:布局管理器的可视化指南
下一页:布局管理器的工作原理