使用布局管理器
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/using.html
布局管理器是实现LayoutManager
接口*的对象,确定容器内组件的大小和位置。尽管组件可以提供大小和对齐提示,但容器的布局管理器最终决定容器内组件的大小和位置。
注意:本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,可以选择使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编写代码并且不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
本节讨论了与使用布局管理器相关的一些常见任务:
-
设置布局管理器
-
向容器添加组件
-
提供大小和对齐提示
-
在组件之间放置空间
-
设置容器的方向
-
选择布局管理器的提示
-
第三方布局管理器
设置布局管理器
通常情况下,您需要关注的唯一容器的布局管理器是JPanel
和内容窗格。每个JPanel
对象在初始化时都会使用FlowLayout
,除非在创建JPanel
时另行指定。内容窗格默认使用BorderLayout
。如果您不喜欢面板或内容窗格使用的默认布局管理器,可以自由更改为其他布局管理器。但是,除非您使用JToolBar
,否则FlowLayout
和BorderLayout
管理器仅适用于原型设计。任何真实的应用程序都需要重新设置布局管理器。再次强调,您应该使用适当的工具来执行此操作,而不是手动编写管理器。
您可以使用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
方法指定哪些参数(如果有的话)。一些布局管理器,如GridBagLayout
和SpringLayout
,需要复杂的设置过程。然而,许多布局管理器只是根据它们添加到容器中的顺序来放置组件。
除了JPanel
和内容窗格之外的 Swing 容器通常提供了 API,您应该使用这些 API 而不是add
方法。例如,不要直接向滚动窗格(或者实际上是其视口)添加组件,而是要么在JScrollPane
构造函数中指定组件,要么使用setViewportView
方法。由于有了这样的专门 API,您不需要知道许多 Swing 容器使用的布局管理器(如果有的话)。(对于好奇的人:滚动窗格实际上使用了一个名为ScrollPaneLayout
的布局管理器。)
有关如何向特定容器添加组件的信息,请参阅该容器的操作指南页面。您可以使用各种组件的使用方法找到组件的操作指南页面。
提供大小和对齐提示
有时,您需要自定义组件向其容器的布局管理器提供的大小提示,以便组件能够被很好地布局。您可以通过指定组件的最小、首选和最大大小来实现这一点。您可以调用组件的设置大小提示方法——setMinimumSize
、setPreferredSize
和setMaximumSize
。或者您可以创建一个子类,重写适当的获取器方法——getMinimumSize
、getPreferredSize
和getMaximumSize
。以下是使组件的最大大小无限制的示例:
component.setMaximumSize(new Dimension(Integer.MAX_VALUE,
Integer.MAX_VALUE));
许多布局管理器不关注组件的请求的最大尺寸。然而,BoxLayout
和SpringLayout
会关注。此外,GroupLayout
提供了明确设置最小、首选或最大尺寸的能力,而无需触及组件。
除了提供大小提示外,您还可以提供对齐提示。例如,您可以指定两个组件的顶部边缘应该对齐。您可以通过调用组件的setAlignmentX
和setAlignmentY
方法,或者通过覆盖组件的getAlignmentX
和getAlignmentY
方法来设置对齐提示。尽管大多数布局管理器会忽略对齐提示,但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
在完全相同的容器中以不同方向布局组件的方式。
默认方向(从左到右)
从右到左方向
支持组件方向的标准布局管理器包括FlowLayout
、BorderLayout
、BoxLayout
、GridBagLayout
和GridLayout
。
注意: 必须注意将组件方向应用于渲染器、编辑器和通过容器层次结构的正常遍历无法访问的任何其他组件。
选择布局管理器的提示
布局管理器有不同的优势和劣势。本节讨论了一些常见的布局场景以及哪些布局管理器可能适用于每种场景。然而,再次强烈建议您使用构建工具来创建您的布局管理器,比如NetBeans IDE Matisse GUI builder,而不是手动编码管理器。下面列出的场景仅供信息参考,以防您想知道不同情况下使用哪种类型的管理器,或者您绝对必须手动编码您的管理器。
如果我们讨论的布局管理器都不适合您的情况,并且您不能使用构建工具,请随意使用您可能编写或找到的其他布局管理器。还要记住,灵活的布局管理器如GridBagLayout
和SpringLayout
可以满足许多布局需求。
场景: 您需要在尽可能多的空间中显示一个组件。
如果它是容器中唯一的组件,请使用GridLayout
或BorderLayout
。否则,BorderLayout
或GridBagLayout
可能是一个很好的选择。
如果使用BorderLayout
,您需要将占用大量空间的组件放在中心位置。使用GridBagLayout
,您需要设置组件的约束条件,使fill=GridBagConstraints.BOTH
。另一种可能性是使用BoxLayout
,使占用大量空间的组件指定非常大的首选大小和最大大小。
场景: 您需要以它们的自然大小在一个紧凑的行中显示几个组件。
考虑使用JPanel
来组合组件,并使用JPanel
的默认FlowLayout
管理器或BoxLayout
管理器。SpringLayout
也适用于这种情况。
场景: 您需要以行和列的方式显示几个相同大小的组件。
GridLayout
非常适合这种情况。
场景: 您需要以行或列的方式显示几个组件,可能在它们之间有不同数量的空间,自定义对齐方式或自定义组件大小。
BoxLayout
非常适合这种情况。
场景: 您需要显示对齐的列,就像在一个类似表单的界面中,一个标签列用于描述相邻列中的文本字段。
SpringLayout
是这种情况的自然选择。几个教程示例中使用的SpringUtilities
类定义了一个makeCompactGrid
方法,让您可以轻松地对齐多行和多列的组件。
场景: 您有一个包含许多组件的复杂布局。
考虑使用非常灵活的布局管理器,如GridBagLayout
或SpringLayout
,或将组件分组到一个或多个JPanel
中以简化布局。如果采用后一种方法,每个JPanel
可能会使用不同的布局管理器。
第三方布局管理器
Swing 社区创建了其他第三方布局管理器,以补充 Java 平台提供的布局管理器。以下列表并非绝对,但下面列出的布局管理器是最受欢迎的:
*早在 JDK 1.1 时引入了第二个接口LayoutManager2
。LayoutManager2
扩展了LayoutManager
,提供了最大尺寸和对齐支持。LayoutManager2
还添加了addLayoutComponent
方法,接受一个Object
,以及invalidateLayout
方法。布局管理器还需要LayoutManager2
提供的通知,因此任何现代布局管理器都需要实现它。
布局管理的工作原理
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/howLayoutWorks.html
注意: 本课程涵盖手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
这里是一个使用LayoutManager2
对容器进行布局管理的示例。
-
布局管理器基本上执行两项任务:
-
计算容器的最小/首选/最大大小。
-
布局容器的子元素。
布局管理器根据提供的约束、容器的属性(如插入)以及子元素的最小/首选/最大大小来执行此操作。如果子元素本身是一个容器,则使用其自身的布局管理器来获取其最小/首选/最大大小并进行布局。
-
-
容器可以是有效的(即,
isValid()
返回 true),也可以是无效的。要使容器有效,所有容器的子元素必须已经布局,并且也必须全部有效。Container.validate
方法可用于验证无效容器。此方法触发容器及其子容器沿组件层次结构向下的布局,并将此容器标记为有效。 -
组件创建后,默认处于无效状态。
Window.pack
方法验证窗口,并首次布局窗口的组件层次结构。
最终结果是为了确定容器的最佳大小,系统确定了包含层次结构底部容器的大小。然后这些大小向上层次结构传播,最终确定容器的总大小。
如果组件的大小发生变化,例如更改字体后,必须调用该组件的revalidate
和repaint
方法来重新调整大小并重绘。revalidate
和repaint
都是线程安全的 您无需从事件分派线程调用它们。
当你在组件上调用revalidate
时,请求会沿着包含层次结构传递,直到遇到一个容器,比如滚动窗格或顶层容器,这些容器不应受到组件调整大小的影响。(这是通过调用容器的isValidateRoot
方法来确定的。)然后对容器进行布局,这会调整重新验证的组件的大小以及所有受影响组件的大小。
如何使用各种布局管理器
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/layoutlist.html
以下每个页面描述了如何使用特定类型的布局管理器。另一种访问这些页面的方法是通过布局管理器可视化指南。
注意: 这节课涵盖了手动编写布局代码,这可能是具有挑战性的。如果你对学习布局管理的所有细节不感兴趣,你可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局你的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果你想手动编写代码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果你有兴趣使用 JavaFX 创建你的 GUI,请参阅JavaFX 中的布局教程。
-
如何使用 BorderLayout
-
如何使用 BoxLayout
-
如何使用 CardLayout
-
如何使用 FlowLayout
-
如何使用 GridBagLayout
-
如何使用 GridLayout
-
如何使用 GroupLayout
-
如何使用 SpringLayout
如何使用 BorderLayout
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/border.html
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么GridBagLayout
被推荐为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
以下图表示了一个使用BorderLayout
类的应用程序的快照。
点击启动按钮以使用Java™ Web Start运行 BorderLayoutDemo(下载 JDK 7 或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
这个演示的完整代码在BorderLayoutDemo.java
文件中。
如前面的图片所示,BorderLayout
对象有五个区域。这些区域由BorderLayout
常量指定:
-
PAGE_START
-
PAGE_END
-
LINE_START
-
LINE_END
-
CENTER
版本说明:
在 JDK 1.4 版本发布之前,各个区域的首选名称不同,从罗盘点(例如,BorderLayout.NORTH
表示顶部区域)到我们示例中使用的常量的较长版本。我们示例中使用的常量是首选的,因为它们是标准的,并且使程序能够适应具有不同方向的语言。
如果窗口被放大,中心区域会尽可能占用所有可用空间。其他区域只会扩展到填满所有可用空间为止。通常,一个容器只使用BorderLayout
对象的一个或两个区域 只有中心,或中心和底部。
以下代码向框架的内容窗格添加组件。因为内容窗格默认使用 BorderLayout
类,所以代码不需要设置布局管理器。完整程序在 BorderLayoutDemo.java
文件中。
...*//Container pane = aFrame.getContentPane()*...
JButton button = new JButton("Button 1 (PAGE_START)");
pane.add(button, BorderLayout.PAGE_START);
//Make the center component big, since that's the
//typical usage of BorderLayout.
button = new JButton("Button 2 (CENTER)");
button.setPreferredSize(new Dimension(200, 100));
pane.add(button, BorderLayout.CENTER);
button = new JButton("Button 3 (LINE_START)");
pane.add(button, BorderLayout.LINE_START);
button = new JButton("Long-Named Button 4 (PAGE_END)");
pane.add(button, BorderLayout.PAGE_END);
button = new JButton("5 (LINE_END)");
pane.add(button, BorderLayout.LINE_END);
指定组件的位置(例如,BorderLayout.LINE_END
)作为 add
方法的参数之一。如果此组件在由 BorderLayout
对象控制的容器中缺失,请确保已指定组件的位置,并且没有其他组件放置在相同位置。
所有使用 BorderLayout
类的教程示例将组件指定为 add
方法的第一个参数。例如:
add(component, BorderLayout.CENTER) //preferred
然而,在其他程序中的代码将组件指定为第二个参数。例如,以下是编写前述代码的替代方式:
add(BorderLayout.CENTER, component) //valid but old fashioned
*or*
add("Center", component) //valid but error prone
BorderLayout API
以下表列出了指定间隙(以像素为单位)的构造函数和方法。
指定间隙
构造函数或方法 | 目的 |
---|---|
BorderLayout(int *horizontalGap*, int *verticalGap*) |
定义具有指定组件间隙的边界布局。 |
setHgap(int) |
设置组件之间的水平间距。 |
setVgap(int) |
设置组件之间的垂直间距。 |
使用 BorderLayout 的示例
以下表列出了使用 BorderLayout
类的代码示例,并提供到相关部分的链接。
示例 | 描述位置 | 注释 |
---|---|---|
BorderLayoutDemo |
本页 | 将一个组件放在五个可能的位置中的每一个。 |
TabbedPaneDemo |
如何使用选项卡窗格 | 其中一个示例,将一个组件放在内容窗格的中心,使组件尽可能大。 |
CheckBoxDemo |
如何使用复选框 | 创建一个使用 BorderLayout 类的 JPanel 对象。将组件放入左侧(实际上是 LINE_START )和中心位置。 |
如何使用 BoxLayout
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果你不想学习布局管理的所有细节,可以选择使用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 的两部分,并确保任何多余的空间都给了滚动窗格。
你可以在示例索引中找到运行 ListDialog 以及其源文件的链接,用于使用 Swing 组件。
以下代码取自ListDialog.java
,布局了 GUI。这段代码位于对话框的构造函数中,该对话框是作为JDialog
子类实现的。粗体代码设置了 Box 布局并向其中添加了组件。
JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(250, 80));
listScroller.setAlignmentX(LEFT_ALIGNMENT);
...
//Lay out the label and scroll pane from top to bottom.
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));
//Lay out the buttons from left to right.
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);
//Put everything together, using the content pane's BorderLayout.
Container contentPane = getContentPane();
contentPane.add(listPane, BorderLayout.CENTER);
contentPane.add(buttonPane, BorderLayout.PAGE_END);
第一行粗体代码创建了一个从上到下的 Box 布局,并将其设置为listPane
的布局管理器。BoxLayout
构造函数的两个参数是它管理的容器和组件将被布局的轴。PAGE_AXIS
常量指定组件应该按照页面上行流动的方向进行布局,由目标容器的ComponentOrientation
属性确定。LINE_AXIS
常量指定组件应该按照文本行的方向进行布局,由目标容器的ComponentOrientation
属性确定。这些常量允许通过以正确的从左到右、从右到左或从上到下的方向为所用语言的容器中的组件进行布局来进行国际化。
接下来的三行粗体代码将标签和滚动窗格添加到容器中,并使用一个刚性区域分隔它们 一个用于在组件之间添加空间的不可见组件。在这种情况下,刚性区域没有宽度,并在标签和滚动窗格之间放置了确切的5 像素
。稍后在使用不可见组件作为填充中讨论了刚性区域。
下一块粗体代码创建了一个从左到右的 Box 布局,并为buttonPane
容器设置了布局。然后代码向容器添加了两个按钮,使用一个刚性区域在按钮之间放置了10 像素
。为了将按钮放置在其容器的右侧,添加到容器的第一个组件是glue。这个 glue 是一个不可见组件,根据需要增长以吸收其容器中的任何额外空间。在使用不可见组件作为填充中讨论了 glue。
作为使用不可见组件的替代方案,有时可以使用空边框来在组件周围创建空间,尤其是面板。例如,前面的代码片段使用空边框在对话框及其内容的所有边缘之间以及内容的两个部分之间放置了10 像素
。边框完全独立于布局管理器。它们只是 Swing 组件如何绘制其边缘并在组件内容和边缘之间提供填充的方式。更多信息请参见如何使用边框。
以下部分更详细地讨论了BoxLayout
:
-
Box 布局特性
-
使用不可见组件作为填充
-
修复对齐问题
-
指定组件大小
-
Box 布局 API
-
使用 Box 布局的示例
不要让BoxLayout
讨论的长度吓到你!你可能已经可以使用BoxLayout
了。如果遇到问题或想利用BoxLayout
的功能,继续阅读。
Box Layout 特点
如前所述,BoxLayout
将组件排列在彼此上方或一行中。在安排组件时,BoxLayout 会考虑组件的对齐方式以及最小、首选和最大尺寸。在本节中,我们将讨论从上到下的布局。相同的概念适用于从左到右或从右到左的布局。只需用 Y 替换 X,宽度替换高度等。
版本说明:在 JDK 版本 1.4 之前,没有为以本地化方式指定框布局轴的常量。相反,在创建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
)的组件的左侧与具有 0.5 X 对齐(Component.CENTER_ALIGNMENT
)的组件的中心对齐,后者与具有 X 对齐为 1.0(Component.RIGHT_ALIGNMENT
)的组件的右侧对齐。这种混合对齐方式在修复对齐问题中进一步讨论。
如果没有任何组件具有最大宽度会怎么样?在这种情况下,如果所有组件具有相同的 X 对齐方式,则所有组件将与其容器一样宽。如果 X 对齐方式不同,则具有 X 对齐为 0.0(左)或 1.0(右)的任何组件将较小。所有具有中间 X 对齐方式(例如中心)的组件将与其容器一样宽。以下是两个示例:
要更好地了解BoxLayout
,您可以运行自己的 BoxLayoutDemo2 实验。
试试这个:
-
单击“启动”按钮以使用Java™ Web Start运行 BoxLayoutDemo2(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
您可以在
BoxLayoutDemo2.java
中查看代码。您将看到一个类似上面的窗口,其中包含三个矩形。每个矩形都是
BLDComponent
的一个实例,它是JComponent
的子类。 -
单击其中一个矩形内部。
这是如何更改矩形的 X 对齐方式。
-
单击窗口底部的复选框。
这将关闭所有矩形的限制尺寸。
-
使窗口变得更高。
这使得矩形的容器比矩形的首选大小之和更大。容器是一个带有红色轮廓的
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) |
这是您通常如何使用每种类型的填充器:
刚性区域
当您希望在两个组件之间有固定大小的空间时,请使用此选项。例如,在从左到右的框中在两个组件之间放置 5 像素,您可以使用以下代码:
container.add(firstComponent);
container.add(Box.createRigidArea(new Dimension(5,0)));
container.add(secondComponent);
注意: Box
类提供了另一种用于在组件之间放置固定空间的填充器:垂直或水平支柱。不幸的是,支柱具有无限的最大高度或宽度(分别用于水平和垂直支柱)。这意味着,如果您在垂直框内使用水平框,水平框有时可能会变得太高。因此,我们建议您使用刚性区域而不是支柱。
粘合剂
使用这个方法可以指定布局中多余的空间应该去哪里。将其视为一种弹性胶水 有弹性和可伸缩性,但除非你拉开它粘附的组件,否则不占用空间。例如,在一个从左到右的盒式布局中,在两个组件之间放置水平粘合剂,可以使任何额外的空间都在这些组件之间,而不是在所有组件的右侧。以下是一个示例,使得从左到右的盒式布局中的空间在两个组件之间,而不是在组件的右侧:
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
控制的两个或更多组件具有不同的默认对齐方式,导致它们对齐不正确。例如,如下所示,如果一个标签和一个面板在一个从上到下的盒式布局中,标签的左边缘默认与面板的中心对齐。
一般来说,由从上到下的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
。前面的图片展示了如果将一个左对齐的组件(如标签)与一个在由上至下控制的容器中的中心对齐组件放在一起会发生什么。
BoxAlignmentDemo
程序提供了修复不匹配对齐问题的示例。通常,只需将有问题的按钮或标签设置为中心对齐即可。例如:
label.setAlignmentX(Component.CENTER_ALIGNMENT);
指定组件尺寸
正如之前提到的,BoxLayout
会关注组件的请求的最小、首选和最大尺寸。在微调布局时,你可能需要调整这些尺寸。
有时需要调整尺寸是显而易见的。例如,按钮的最大尺寸通常与其首选尺寸相同。如果希望在有额外空间时将按钮绘制得更宽,那么需要更改其最大尺寸。
然而,有时需要调整尺寸并不那么明显。你可能会在框布局中得到意想不到的结果,而不知道原因。在这种情况下,通常最好首先将问题视为对齐问题。如果调整对齐方式没有帮助,那么可能存在尺寸问题。我们稍后会进一步讨论这个问题。
注意: 虽然BoxLayout
会关注组件的最大尺寸,但许多布局管理器不会。例如,如果你将一个按钮放在BorderLayout
的底部,那么按钮的宽度可能会超过其首选宽度,无论按钮的最大尺寸是多少。另一方面,BoxLayout
永远不会使按钮的宽度超过其最大尺寸。
你可以通过两种方式更改最小、首选和最大尺寸:
-
通过调用适当的
set*Xxx*Size
方法(由JComponent
类定义)。例如:comp.setMinimumSize(new Dimension(50, 25)); comp.setPreferredSize(new Dimension(50, 25)); comp.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
-
通过覆盖适当的
get*Xxx*Size
方法。例如:*...//in a subclass of a component class:* public Dimension getMaximumSize() { size = getPreferredSize(); size.width = Short.MAX_VALUE; return size; }
如果你在使用框布局时遇到问题,并且已经排除了对齐问题,那么问题很可能与尺寸有关。例如,如果由框布局控制的容器占用了太多空间,那么容器中的一个或多个组件可能需要限制其最大尺寸。
您可以使用两种技术来追踪箱式布局中的尺寸问题:
-
在问题的 Swing 组件外部添加花哨的线条边框。这样你就可以看到它们的真实大小。例如:
comp.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(Color.red), comp.getBorder()));
-
使用
System.out.println
来打印组件的最小、首选和最大尺寸,也许还有它们的边界。
Box 布局 API
以下表格列出了常用的BoxLayout
和Box
构造函数和方法。使用箱式布局的 API 分为以下几类:
-
创建
BoxLayout
对象 -
创建空间填充器
-
其他有用的方法
创建BoxLayout
对象
构造函数或方法 | 目的 |
---|---|
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 。 |
创建空间填充器
这些方法在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 布局的示例
以下表格列出了使用箱式布局的许多示例。
示例 | 描述位置 | 注释 |
---|---|---|
BoxLayoutDemo2 | 本页 | 使用箱式布局创建一个居中的列组件。 |
BoxAlignmentDemo | 本页 | 演示如何解决常见的对齐问题。 |
BoxLayoutDemo | 本页面 | 让您尝试对齐和最大尺寸。 |
ListDialog | 本页面 | 一个简单但逼真的例子,展示了如何同时使用自顶向下箱式布局和左右箱式布局。使用水平粘合剂、刚性区域和空边框。还设置了组件的 X 对齐方式。 |
InternalFrameEventDemo | 如何编写内部框架监听器 | 使用自顶向下布局来将按钮和滚动窗格居中放置在内部框架中。 |
MenuGlueDemo | 自定义菜单布局 | 展示如何使用粘合组件将菜单右对齐在菜单栏中。 |
MenuLayoutDemo | 自定义菜单布局 | 展示如何通过将菜单栏更改为使用自顶向下的箱式布局,以及上下文菜单更改为使用左右的箱式布局来自定义菜单布局。 |
ConversionPanel.java 在 Converter 演示中 |
如何使用面板 | 通过将组件的宽度设置为相同,以及它们容器的宽度设置为相同,来在不同的箱式布局控制容器中对齐两个组件。 |
如何使用 CardLayout
注意: 本课程涵盖手动编写布局代码,这可能具有挑战性。如果您对学习布局管理的所有细节不感兴趣,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
以下图表示一个应用程序的快照,该应用程序使用CardLayout
类在两个面板之间切换。
点击“启动”按钮以使用Java™ Web Start运行 CardLayoutDemo(下载 Java SE)。或者,要自行编译和运行示例,请参考示例索引。
这个演示的完整代码在CardLayoutDemo.java
文件中。
CardLayout
类管理两个或多个组件(通常是JPanel
实例),它们共享相同的显示空间。使用CardLayout
类时,让用户通过使用组合框在组件之间进行选择。CardLayoutDemo
应用程序是一个示例,用于说明此功能。
另一种完成相同任务的方法是使用选项卡窗格。下图显示了前面示例的选项卡窗格版本:
因为选项卡窗格提供了自己的 GUI,所以使用选项卡窗格比使用CardLayout
类更简单。例如,使用选项卡窗格实现前面的示例会导致代码行数更少的程序。
单击“启动”按钮以使用Java™ Web Start运行 TabDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
此演示的完整代码位于TabDemo.java
文件中。
从概念上讲,CardLayout
管理的每个组件都像一叠扑克牌或交换卡片,任何时候只有顶部卡片可见。您可以通过以下任何方式选择显示的卡片:
-
通过请求第一张或最后一张卡片,按照添加到容器的顺序
-
通过向前或向后翻转卡片堆栈来选择卡片。
-
通过指定具有特定名称的卡片
CardLayoutDemo
类使用最后一种方案。
来自CardLayoutDemo.java
应用程序的以下代码片段创建了CardLayout
对象及其管理的组件。
*//Where instance variables are declared:*
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
final static String TEXTPANEL = "Card with JTextField";
*//Where the components controlled by the CardLayout are initialized:*
//Create the "cards".
JPanel card1 = new JPanel();
...
JPanel card2 = new JPanel();
...
//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
cards.add(card2, TEXTPANEL);
要将组件添加到CardLayout
对象管理的容器中,请指定一个标识要添加的组件的字符串。例如,在此演示中,第一个面板的字符串是"Card with JButtons"
,第二个面板的字符串是"Card with JTextField"
。在此演示中,这些字符串也在组合框中使用。
要选择CardLayout
对象显示的组件,请在您的代码示例中添加额外的代码:
*//Where the GUI is assembled:*
//Put the JComboBox in a JPanel to get a nicer look.
JPanel comboBoxPane = new JPanel(); //use FlowLayout
String comboBoxItems[] = { BUTTONPANEL, TEXTPANEL };
JComboBox cb = new JComboBox(comboBoxItems);
cb.setEditable(false);
cb.addItemListener(this);
comboBoxPane.add(cb);
...
pane.add(comboBoxPane, BorderLayout.PAGE_START);
pane.add(cards, BorderLayout.CENTER);
...
//Method came from the ItemListener class implementation,
//contains functionality to process the combo box item selecting
public void itemStateChanged(ItemEvent evt) {
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, (String)evt.getItem());
}
此示例显示,要使用CardLayout
类的show
方法,必须设置当前可见的组件。show
方法中的第一个参数是CardLayout
控制的容器,即CardLayout
管理的组件的容器。第二个参数是标识要显示的组件的字符串。这个字符串与将组件添加到容器时使用的字符串相同。
CardLayout API
以下表格列出了用于选择组件的CardLayout
类方法。对于每个方法,第一个参数是CardLayout
是布局管理器的容器(CardLayout
控制的卡片的容器)。
方法 | 目的 |
---|---|
first (Container *parent*) |
翻转到容器的第一张卡片。 |
next (Container *parent*) |
翻转到容器的下一张卡片。如果当前可见的卡片是最后一张,则此方法将翻转到布局中的第一张卡片。 |
previous (Container *parent*) |
翻转到容器的上一张卡片。如果当前可见的卡片是第一张,则此方法将翻转到布局中的最后一张卡片。 |
last (Container *parent*) |
翻转到容器的最后一张卡片。 |
show (Container *parent*, String *name*) |
使用指定的 name 使用 addLayoutComponent 方法添加到此布局中的组件进行翻转。 |
使用 CardLayout 的示例
在这个教程中,只有一个示例使用了 CardLayout
,即 CardLayoutDemo
。一般来说,我们的示例使用 选项卡面板 而不是 CardLayout
,因为选项卡面板提供了自己的 GUI。
如何使用流式布局
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
FlowLayout
类提供了一个非常简单的布局管理器,默认情况下由JPanel
对象使用。以下图表示使用流式布局的应用程序的快照:
单击“启动”按钮以使用Java™ Web Start运行FlowLayoutDemo
(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
此演示的完整代码位于FlowLayoutDemo.java
文件中。
FlowLayout
类将组件放在一行中,大小为它们的首选大小。如果容器中的水平空间太小,无法将所有组件放在一行中,FlowLayout
类将使用多行。如果容器比一行组件所需的宽度更宽,则默认情况下,该行在容器内水平居中。要指定行是左对齐还是右对齐,请使用带有对齐参数的FlowLayout
构造函数。FlowLayout
类的另一个构造函数指定在组件周围放置多少垂直或水平填充。
下面的代码片段创建了一个FlowLayout
对象和它管理的组件。
FlowLayout experimentLayout = new FlowLayout();
...
compsToExperiment.setLayout(experimentLayout);
compsToExperiment.add(new JButton("Button 1"));
compsToExperiment.add(new JButton("Button 2"));
compsToExperiment.add(new JButton("Button 3"));
compsToExperiment.add(new JButton("Long-Named Button 4"));
compsToExperiment.add(new JButton("5"));
选择“从左到右”或“从右到左”选项,并单击“应用方向”按钮以设置组件的方向。以下代码片段将“从左到右”组件方向应用于experimentLayout
。
compsToExperiment.setComponentOrientation(
ComponentOrientation.LEFT_TO_RIGHT);
流式布局 API
以下表列出了FlowLayout
类的构造函数。
构造函数 | 目的 |
---|---|
FlowLayout() |
构造一个具有居中对齐和水平垂直间隙的默认大小为5 像素 的新FlowLayout 对象。 |
FlowLayout(int *align*) |
创建一个新的流式布局管理器,具有指定的对齐方式和水平垂直间隙,默认大小为5 像素 。对齐参数可以是FlowLayout.LEADING ,FlowLayout.CENTER 或FlowLayout.TRAILING 。当FlowLayout 对象控制具有从左到右组件方向(默认)的容器时,LEADING 值指定左对齐的组件,TRAILING 值指定右对齐的组件。 |
FlowLayout (int *align*, int *hgap*, int *vgap*) |
创建一个新的流式布局管理器,具有指定的对齐方式和指定的水平和垂直间隙。hgap 和vgap 参数指定组件之间要放置的像素数。 |
使用 FlowLayout 的示例
以下表格列出了使用FlowLayout
类的代码示例,并提供到相关部分的链接。
示例 | 描述位置 | 备注 |
---|---|---|
FlowLayoutDemo |
本页 | 设置内容窗格使用FlowLayout 。如果将RIGHT_TO_LEFT 常量设置为true 并重新编译,您可以看到FlowLayout 如何处理具有从右到左组件方向的容器。 |
CardLayoutDemo |
如何使用 CardLayout | 在BorderLayout 的顶部部分很好地居中一个组件,并将组件放在使用FlowLayout 的JPanel 中。 |
ButtonDemo |
如何使用按钮、复选框和单选按钮 | 使用JPanel 的默认FlowLayout 。 |
TextInputDemo |
如何使用格式化文本字段 | 使用一个右对齐的FlowLayout 呈现两个按钮的面板。 |
如何使用 GridBagLayout
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您对学习布局管理的所有细节不感兴趣,您可能更喜欢使用 GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编写代码而不想使用 GroupLayout
,那么推荐使用 GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建您的 GUI,请参阅 JavaFX 中的布局。
这是一个使用 GridBagLayout
的示例图片。
点击“启动”按钮以使用 Java™ Web Start 运行 GridBagLayoutDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考 示例索引。
GridBagDemo
的代码位于 GridBagLayoutDemo.java
中。
GridBagLayout
是 Java 平台提供的最灵活 也是最复杂 布局管理器之一。GridBagLayout
将组件放置在行和列的网格中,允许指定的组件跨越多行或多列。并非所有行都必须具有相同的高度。同样,并非所有列都必须具有相同的宽度。基本上,GridBagLayout
将组件放置在网格中的矩形(单元格)中,然后使用组件的首选大小来确定单元格的大小。
以下图显示了前面小程序的网格。您可以看到,网格有三行三列。第二行的按钮跨越所有列;第三行的按钮跨越了右侧两列。
如果您按照下图所示放大窗口,您会注意到包含按钮 5 的底部行获得了所有新的垂直空间。新的水平空间均匀分配给所有列。此调整大小行为基于程序为GridBagLayout
中的各个组件分配的权重。您还会注意到每个组件占用所有可用的水平空间 但不占用所有可用的垂直空间(正如您可以看到的按钮 5)。此行为也由程序指定。
程序指定其组件的大小和位置特征的方式是为每个组件指定约束条件。在组件上设置约束的首选方法是使用Container.add
变体,传递一个GridBagConstraints
对象,如下一节所示。
以下各节解释了您可以设置的约束条件并提供了示例。
指定约束条件
以下代码是典型的使用GridBagLayout
的容器中的内容。您将在下一节看到更详细的示例。
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
*//For each component to be added to this container:*
*//...Create the component...*
*//...Set instance variables in the GridBagConstraints instance...*
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("Button 1");
if (shouldWeightX) {
c.weightx = 0.5;
}
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 2");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 1;
c.gridy = 0;
pane.add(button, c);
button = new JButton("Button 3");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
pane.add(button, c);
button = new JButton("Long-Named Button 4");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40; //make this component tall
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; //reset to default
c.weighty = 1.0; //request any extra vertical space
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0); //top padding
c.gridx = 1; //aligned with button 2
c.gridwidth = 2; //2 columns wide
c.gridy = 2; //third row
pane.add(button, c);
此示例对GridBagLayout
管理的所有组件使用一个GridBagConstraints
实例,但在实际情况中,建议不要重用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 API
GridBagLayout
和GridBagConstraints
类各自只有一个构造函数,没有参数。您不是在GridBagConstraints
对象上调用方法,而是操作其实例变量,如指定约束中所述。通常,您在GridBagLayout
对象上调用的唯一方法是setConstraints
,如示例解释中所示。
使用 GridBagLayout 的示例
您可以在本教程中找到使用GridBagLayout
的示例。以下表格列出了一些示例。
示例 | 描述位置 | 注释 |
---|---|---|
GridBagLayoutDemo |
本节 | 使用许多功能——权重、插入、内部填充、水平填充、精确单元格定位、多列单元格和锚定(组件在单元格内的定位)。 |
TextSamplerDemo |
使用文本组件 | 对齐两对标签和文本字段,并在容器的整个宽度上添加一个标签。 |
ContainerEventDemo |
如何编写容器监听器 | 使用权重、填充和相对定位在容器中定位五个组件。 |
如何使用 GridLayout
注意: 本课程涵盖手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码且不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
以下图表示使用GridLayout
类的应用程序的快照。
点击“启动”按钮以使用Java™ Web Start运行GridLayoutDemo
(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
此演示的完整代码位于GridLayoutDemo.java
文件中。
GridLayout
对象将组件放置在单元格网格中。每个组件占据其单元格中的所有可用空间,每个单元格的大小完全相同。如果调整GridLayoutDemo
窗口的大小,GridLayout
对象会更改单元格大小,以使单元格尽可能大,给定容器可用的空间。
下面的代码片段创建了GridLayout
对象和其管理的组件。
GridLayout experimentLayout = new GridLayout(0,2);
...
compsToExperiment.setLayout(experimentLayout);
compsToExperiment.add(new JButton("Button 1"));
compsToExperiment.add(new JButton("Button 2"));
compsToExperiment.add(new JButton("Button 3"));
compsToExperiment.add(new JButton("Long-Named Button 4"));
compsToExperiment.add(new JButton("5"));
GridLayout
类的构造函数创建一个具有两列并且必要行数的实例。
使用组合框设置组件周围的垂直或水平填充量,然后单击“应用间隙”按钮。以下代码片段显示了如何使用GridLayout
类的setVgap
和setHgap
方法处理您的选择:
applyButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//Get the horizontal gap value
String horGap = (String)horGapComboBox.getSelectedItem();
//Get the vertical gap value
String verGap = (String)verGapComboBox.getSelectedItem();
//Set up the horizontal gap value
experimentLayout.setHgap(Integer.parseInt(horGap));
//Set up the vertical gap value
experimentLayout.setVgap(Integer.parseInt(verGap));
//Set up the layout of the buttons
experimentLayout.layoutContainer(compsToExperiment);
}
});
GridLayout
API
以下表格列出了指定行数和列数的GridLayout
类的构造函数。
GridLayout
类的构造函数
构造函数 | 目的 |
---|---|
GridLayout(int *rows*, int *cols*) |
创建具有指定行数和列数的网格布局。布局中的所有组件都具有相同的大小。rows 和cols 中的一个,但不是两者都可以为零,这意味着可以在一行或一列中放置任意数量的对象。 |
GridLayout(int *rows*, int *cols*, int *hgap*, int *vgap*) |
创建具有指定行数和列数的网格布局。此外,水平和垂直间隙设置为指定值。水平间隙放置在每列之间。垂直间隙放置在每行之间。 |
GridLayout
类有两个构造函数:
使用GridLayout
的示例
下表列出了使用GridLayout
类的代码示例,并提供到相关部分的链接。
示例 | 描述位置 | 注释 |
---|---|---|
GridLayoutDemo |
本页面 | 使用了 2 列网格。 |
ComboBoxDemo2 |
如何使用组合框 | 其中一个示例,使用 1x1 网格使组件尽可能大。 |
LabelDemo |
如何使用标签 | 使用了 3 行网格。 |
如何使用 GroupLayout
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/group.html
GroupLayout
是为 GUI 构建器(如 NetBeans IDE 提供的 GUI 构建器 Matisse)开发的布局管理器。尽管布局管理器最初是为适应 GUI 构建器的需求而设计的,但它也适用于手动编码。本讨论将教你GroupLayout
的工作原理,并向你展示如何使用GroupLayout
构建 GUI,无论你选择使用像 Matisse 这样的 GUI 构建器还是编写自己的代码。
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您对学习布局管理的所有细节不感兴趣,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编写代码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
设计原则:独立维度
GroupLayout
分别处理水平和垂直布局。每个维度的布局都是独立定义的。在定义水平布局时,你不需要担心垂直维度,反之亦然,因为沿着每个轴的布局完全独立于沿着另一个轴的布局。
当只关注一个维度时,你只需一次解决一半的问题。这比同时处理两个维度要容易。这意味着,当然,每个组件在布局中需要定义两次。如果忘记这样做,GroupLayout
将生成异常。
布局组织:分层组
GroupLayout
使用两种类型的布局——顺序和并行,结合了分层组合。
-
采用顺序排列,组件就像
BoxLayout
或FlowLayout
沿一个轴一样简单地一个接一个地放置。每个组件的位置都是相对于前一个组件定义的。 -
第二种方式将组件并排放置——在同一空间中叠加。它们可以沿垂直轴基线对齐、顶部对齐或底部对齐。沿水平轴,如果组件大小不同,它们可以左对齐、右对齐或居中对齐。
通常,沿一个维度并排放置的组件在另一个维度上是顺序排列的,以避免重叠。
这两种布局之所以强大,是因为它们可以被嵌套层次化。为此,GroupLayout
定义了布局组。一个组可以是顺序的或并行的,并且可以包含组件、其他组和间隙(下面讨论)。
顺序组的大小是包含元素的大小之和,而并行组的大小对应于最大元素的大小(尽管,根据元素和基线的位置,基线对齐组的大小可能比最大元素稍大一些)。
定义布局意味着定义组件如何通过组合顺序和并行排列进行分组。
让我们用一个简单的例子来看看它在实践中是如何工作的。
一个例子
让我们从一些简单的东西开始,只有一排中的三个组件:
我们将使用组来表示此布局。从水平轴开始,很容易看到有一个从左到右排列的顺序组,包含 3 个组件。沿着垂直轴,有一个相同位置、大小和基线的并行组,包含相同的 3 个组件:
在伪代码中,布局规范可能看起来像这样(真正的代码在下面的编写代码部分):
horizontal layout = sequential group { c1, c2, c3 }
vertical layout = parallel group (BASELINE) { c1, c2, c3 }
这说明了前面提到的一个原则:在一个维度上顺序组合的组件通常在另一个维度上形成并行组。
现在让我们再添加一个组件 C4,与 C3 左对齐:
沿着水平轴,新组件占据与 C3 相同的水平空间,以便与 C3 形成并行组。沿着垂直轴,C4 与最初的三个组件的并行组形成顺序组。
在伪代码中,布局规范现在看起来像这样:
horizontal layout = sequential group { c1, c2, parallel group (LEFT) { c3, c4 } }
vertical layout = sequential group { parallel group (BASELINE) { c1, c2, c3 }, c4 }
现在您了解了使用GroupLayout
设计布局的最重要方面。还有一些细节需要解释:如何添加间隙,如何定义大小和调整大小行为,如何定义对齐布局,以及如何编写真实代码。
间隙
间隙可以被视为具有特定大小的不可见组件。可以像组件或其他组件一样向组中添加任意大小的间隙。使用间隙,您可以精确控制组件之间的距离或与容器边框的距离。
GroupLayout
还定义了自动间隙,这些间隙对应于相邻组件之间(或组件与容器边框之间)的首选距离。这样的间隙的大小是动态计算的,基于应用程序使用的外观和感觉(LayoutStyle
类用于此)。使用自动(首选)间隙有两个优点:您不必指定间隙的像素大小,它们会自动调整到 UI 运行的外观和感觉,反映实际的外观和感觉指南。
GroupLayout
区分两个组件之间的首选间隙和组件与容器边框之间的首选间隙。在GroupLayout
API 中有相应的方法用于添加这些间隙(addPreferredGap
和setContainerGap
)。有三种类型的组件间隙:相关,不相关和缩进。LayoutStyle.ComponentPlacement
枚举定义了用作addPreferredGap
方法参数的相应常量:RELATED
,UNRELATED
和INDENT
。相关和不相关间隙之间的区别仅在于大小 - 不相关组件之间的距离稍大一些。缩进表示当一个组件位于另一个组件下方并带有缩进时,两个组件之间的首选水平距离。
如上所述,GroupLayout
可以自动插入间隙 - 如果您没有显式添加自己的间隙,它会为您添加相关的首选间隙。但这不是默认行为。您必须通过在GroupLayout
上调用setAutoCreateGaps(true)
和setAutoCreateContainerGaps(true)
来打开此功能。然后您将自动获得正确的间距。
编写代码
现在,让我们看一下创建上述布局的实际代码。
假设我们有一个名为panel
的容器和已经呈现的相同四个组件(c1
,c2
,c3
和c4
)。首先,我们创建一个新的GroupLayout
对象并将其与面板关联:
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
我们指定自动插入间隙:
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
然后,我们定义组并添加组件。我们使用setHorizontalGroup
和setVerticalGroup
方法为每个维度建立根组。通过createSequentialGroup
和createParallelGroup
方法创建组。使用addComponent
方法将组件添加到组中。
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addComponent(c1)
.addComponent(c2)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(c3)
.addComponent(c4))
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(c1)
.addComponent(c2)
.addComponent(c3))
.addComponent(c4)
);
您可以为平行组指定对齐方式。它可以是GroupLayout.Alignment
枚举中定义的以下常量之一:LEADING
,TRAILING
,CENTER
和BASELINE
。这些常量用于两个维度,并取决于组件方向是从左到右还是从右到左(从上到下还是从下到上)。例如,如果水平(垂直)组件方向是从左到右(从上到下),LEADING
表示左(上),而TRAILING
表示右(下)。CENTER
表示在两个维度上“居中”。如果不指定对齐方式,将使用LEADING
。BASELINE
对齐方式仅在垂直维度上有效。
注意:
组布局中的对齐仅对不同大小的组件有意义。相同大小的组件将自动对齐到每个GroupLayout.Alignment
常量。
有关代码的一些注释:
-
您不需要直接将组件添加到容器中 - 当使用其中一个 addComponent 方法时,这将隐式完成。
-
注意
addComponent
方法的链式调用用于填充组。addComponent
方法总是返回调用它的组。由于这一点,你不需要使用局部变量来保存组。 -
缩进代码是个好主意,这样可以更容易看到组的层次结构。给每个组件一个新行,在层次结构中的每个新组添加一个缩进级别。一个好的源代码编辑器会帮助你匹配括号来关闭
createXXXGroup
方法。遵循这些简单规则,更容易添加新组件或移除现有组件。
组件大小和可调整性
在布局中可调整大小的组件数量没有限制。
在GroupLayout
中,每个组件的大小受到三个值的限制;最小大小、首选大小和最大大小。这些大小控制组件在布局中的调整大小。GroupLayout.addComponent(...)
方法允许指定大小约束。
如果没有明确指定,布局会通过使用组件的getMinimumSize()
、getPreferredSize()
和getMaximumSize()
方法来询问组件的默认大小。对于大多数组件,比如使JTextField
可调整大小或JButton
固定大小,你不需要指定任何内容,因为这些组件本身具有默认的调整大小行为。另一方面,你可以覆盖默认行为。例如,你可以使JTextField
固定大小或JButton
可调整大小。
GroupLayout
定义了提供对调整大小行为精确控制的常量。它们可以作为addComponent(Component comp, int min, int pref, int max)
方法的参数使用。以下是两个示例:
-
强制组件可调整大小(允许缩小和增长):
*group*.addComponent(component, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ...
这允许组件在零大小(最小)到任意大小(
Short.MAX_VALUE
作为最大大小表示“无限”)之间调整大小。如果我们不希望组件在其默认最小大小以下缩小,我们会在第二个参数中使用GroupLayout.DEFAULT_SIZE
而不是0
。 -
要使组件固定大小(禁止调整大小):
group.addComponent(component, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ...
在这些示例中,组件的初始大小不会改变,其默认大小是组件的首选大小。如果我们想要为组件指定特定大小,我们会在第二个参数中指定,而不是使用GroupLayout.DEFAULT_SIZE
。
可调整大小的间隙
指定大小和可调整性也适用于间隙,包括首选间隙。例如,你可以指定两个组件之间的首选间隙,它就像一个弹簧,将组件推开(到容器的相反侧)。两个组件的首选距离仅用作间隙的最小大小。请看下面的代码片段:
layout.createSequentialGroup()
.addComponent(c1)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(c2);
并排组大小
放置在平行组中的可调整大小的元素被拉伸以填充由组中最大元素确定的空间,因此它们最终以相同大小对齐。GroupLayout
还提供了控制是否应调整封闭平行组本身的功能。如果组调整大小被抑制,它会阻止包含的元素超过组的首选大小。这样,您可以使一组组件在两侧对齐,或者限制单个组件具有相同的大小。
让我们尝试使我们的例子中的两个组件(水平维度上的c3
和c4
)大小相同:
layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(c3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(c4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
底层机制的工作方式如下:
-
平行组的大小设置为最大元素的首选大小;因此在我们的例子中是
c4
的首选大小。 -
可调整大小的元素被拉伸到组的大小。在我们的例子中,只有
c3
被有效地拉伸,c4
的大小已经对应于组的大小。
结果,c3
和c4
将具有相同的宽度。组件不会进一步调整大小,因为平行组本身不可调整大小(上面createParallelGroup
方法的第二个参数为false
)。
给细心读者的问题:为什么在这个例子中我们将平行组中的两个组件都定义为可调整大小?似乎只有c3
可调整大小就足够了,因为c4
无论如何都不会被拉伸...
答案是:由于平台和本地化的独立性。否则,我们将不得不依赖于c4
组件始终比c3
大。但是当应用程序在不同平台上运行或被翻译成另一种语言时,这可能会发生变化。通过使两个组件都可调整大小,它们会相互调整,无论哪一个在特定时刻更大。
使组件大小相同
前面的情况是特殊的,因为组件在同一个平行组中。但是如果我们希望不相关的组件具有相同的大小怎么办?显然,通过分组不能始终保证相同的大小。对话框底部一行中的“确定”和“取消”按钮就是一个很好的例子。为此,GroupLayout
提供了一个linkSize
方法。该方法允许将任意组件的大小链接在一起,而不管它们放置在何处。链接组件的结果大小根据最大组件设置。例如:
layout.linkSize(SwingConstants.HORIZONTAL, c3, c4);
在这个例子中,尺寸在水平维度上是有选择性地链接的。
运行时更改您的 GUI
有两个重要的方法可以在运行时对 GUI 进行更改,replace()
和 setHonorsVisibility()
。使用这两种方法,您可以在运行时交换组件或更改组件的可见性,并使 GUI 相应地重新排列。
replace(Component existingComponent, Component newComponent)
用新组件替换现有组件。动态布局所需的常见操作之一是能够像这样替换组件。例如,也许复选框在显示图形或树的组件之间切换。 GroupLayout
通过 replace()
方法使这种情况变得简单。您可以在不重新创建所有组的情况下交换组件。
用户界面中的另一个常见操作是动态更改组件的可见性。也许组件只有在用户完成表单的早期部分时才显示。为了避免在这种情况下组件移动,应该占用空间,无论组件的可见性如何。 GroupLayout
提供了两种配置不可见组件处理方式的方法。 setHonorsVisibility(boolean)
方法全局设置了不可见组件的处理方式。默认值为 true,表示不可见组件被视为不存在。另一方面,值为 false 为不可见组件提供空间,将其视为可见。 setHonorsVisibility(Component,Boolean)
方法可用于在特定组件级别配置行为。为了确定如何处理可见性,GroupLayout
首先检查组件是否已指定值,如果没有,则检查全局属性的设置。
一些历史:
Java 标准版 6 中的 GroupLayout
由三个不同的工作部分组成:获取组件基线的能力,获取组件之间首选间隔的能力(LayoutStyle
),以及 GroupLayout
。这项工作最初是作为一个开源项目在 java.net/projects/swing-layout/
上完成的。
NetBeans 5.0 通过 swing-layout 项目支持 GroupLayout
。由于这项工作的成功,所有三个部分都已合并到了 Java 标准版 6 中的 GroupLayout
中。Java SE 6 中的 GroupLayout
与 swing-layout 中的主要区别在于包名称和方法名称。NetBeans 5.5 提供了针对 Java SE 6 中的 GroupLayout
或 swing-layout 中的 GroupLayout
的定位能力。NetBeans 定位的版本取决于项目定位的 Java 平台版本。定位 Java SE 6 的项目使用 Java SE 中的 GroupLayout
,否则使用 swing-layout 中的 GroupLayout
。
一个 GroupLayout 示例
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/groupExample.html
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您对学习布局管理的所有细节不感兴趣,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅JavaFX 中的布局。
作为使用GroupLayout
创建 GUI 的示例,让我们为这个“查找”对话框创建一个布局:
横向布局
从左到右检查水平维度,我们可以看到有 3 个组成序列。第一个实际上不是一个组,只是一个组件--标签。第二个是包含文本字段和复选框的组(我们稍后将对其进行分解)。第三个是两个按钮的组。如下图所示:
让我们用代码勾画出顺序组。请注意,GroupLayout.Alignment.LEADING
对应于水平维度中的左对齐。还请注意,我们不指定间隙,假设自动插入间隙功能已打开。
layout.setHorizontalGroup(layout.createSequentialGroup()
.addComponent(label)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);
现在让我们分解中间的组。这是最难的部分。有一个文本字段与两个包含两个复选框的并行组序列。请参考以下插图:
让我们添加相应的代码:
layout.setHorizontalGroup(layout.createSequentialGroup()
.addComponent(label)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(textField)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(caseCheckBox)
.addComponent(wholeCheckBox))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(wrapCheckBox)
.addComponent(backCheckBox))))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);
我们希望文本字段可以调整大小,但由于JTextField
默认返回正确的最大大小,这是自动发生的。
右侧剩余的组很简单:只包含两个按钮。以下是代码:
layout.setHorizontalGroup(layout.createSequentialGroup()
.addComponent(label)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(textField)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(caseCheckBox)
.addComponent(wholeCheckBox))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(wrapCheckBox)
.addComponent(backCheckBox))))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(findButton)
.addComponent(cancelButton))
);
最后,我们希望按钮始终保持相同大小,因此让我们将它们链接起来:
layout.linkSize(SwingConstants.HORIZONTAL, findButton, cancelButton);
现在我们完成了水平维度。让我们切换到垂直维度。从现在开始,我们只需要考虑 y 轴。
纵向布局
在纵向维度上,我们从上到下检查布局。我们绝对希望第一行上的所有组件都对齐在基线上。因此,在垂直轴上,有一个基线组的序列,然后是剩余组件的一组。请参考以下图片。
让我们勾画出代码。首先,我们需要定义两个并行组。请注意,GroupLayout.Alignment.LEADING
对应于垂直维度中的顶部对齐。
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);
我们可以立即填充基线组:
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(label)
.addComponent(textField)
.addComponent(findButton))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);
现在让我们看看底部组。请注意,取消按钮与复选框不在共享基线上;它与顶部对齐。因此,第二个平行组包括按钮和两个基线组的顺序组,其中包含复选框:
相应的代码如下所示:
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(label)
.addComponent(textField)
.addComponent(findButton))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(caseCheckBox)
.addComponent(wrapCheckBox))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(wholeCheckBox)
.addComponent(backCheckBox)))
.addComponent(cancelButton))
);
因此,我们创建了一个完整的布局,包括调整大小行为,而不需要指定一个像素的数字——一个真正的跨平台布局。请注意,我们不需要指定组件之间的间隙,我们会自动获得正确的间距,并根据外观和感觉指南。这是查找对话框布局的完整代码:
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addComponent(label)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(textField)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(caseCheckBox)
.addComponent(wholeCheckBox))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(wrapCheckBox)
.addComponent(backCheckBox))))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(findButton)
.addComponent(cancelButton))
);
layout.linkSize(SwingConstants.HORIZONTAL, findButton, cancelButton);
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(label)
.addComponent(textField)
.addComponent(findButton))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(caseCheckBox)
.addComponent(wrapCheckBox))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(wholeCheckBox)
.addComponent(backCheckBox)))
.addComponent(cancelButton))
);
这是完整的Find.java
文件。您可以编译并运行它。尝试水平调整对话框的大小,看看布局如何自动调整到新的大小。
如何使用 SpringLayout
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/spring.html
注意:本课程涵盖手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布置您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么建议使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅使用 JavaFX 中的布局。
SpringLayout
类是在 JDK 版本 1.4 中添加的,用于支持 GUI 构建器中的布局。SpringLayout
是一个非常灵活的布局管理器,可以模拟其他布局管理器的许多功能。但是,SpringLayout
是非常低级的,因此您真的应该只在 GUI 构建器中使用它,而不是尝试手动编写弹簧布局管理器。
本节以一个简单的示例开始,展示创建第一个弹簧布局所需记住的所有事项,以及当您忘记它们时会发生什么!后来,它介绍了几种不同类型网格中布置组件的实用方法。
这里是我们将要涵盖的一些布局的图片:
弹簧布局的工作原理
Spring 布局通过在组件边缘之间定义方向关系或约束来完成其工作。例如,您可以定义一个组件的左边缘与另一个组件的右边缘之间的固定距离(比如 5 像素)。
在SpringLayout
中,每个边缘的位置取决于另一个边缘的位置。如果随后添加约束以为边缘创建新的绑定,则将丢弃先前的绑定,边缘仍然依赖于单个边缘。
与许多布局管理器不同,SpringLayout
不会自动设置其管理的组件的位置。如果您手动编写使用SpringLayout
的 GUI,请记但通过约束西/东和北/南位置来初始化组件位置。根据您使用的约束,您可能还需要显式设置容器的大小。
组件定义了边缘属性,这些属性由Spring
实例连接。每个弹簧有四个属性 其最小、首选和最大值,以及其实际(当前)值。与每个组件相关联的弹簧被收集到一个SpringLayout.Constraints
对象中。
Spring
类的一个实例包含三个特征其行为的属性:最小值、首选值和最大值。这些属性中的每一个可能参与根据一系列规则定义其第四个值属性。
Spring
类的一个实例可以被视为一个机械弹簧,当弹簧被压缩或拉伸远离其首选值时,它提供一个校正力。这个力被建模为距离首选值的线性函数,但具有两个不同的常数 -- 一个用于压缩力,一个用于张力力。这些常数由弹簧的最小值和最大值指定,以便当弹簧处于其最小值时产生与其处于最大值时产生的相等且相反的力。因此,首选值和最小值之间的差值代表了弹簧可以被压缩的容易程度。其最大值和首选值之间的差值表示了Spring
可以被拉伸的容易程度。
基于此,SpringLayout
可以被视为一组通过边缘上的一组弹簧连接的对象。
示例:SpringDemo
这一部分将带您了解为使用SpringLayout
指定容器约束条件的典型步骤。第一个示例,SpringDemo1.java
,是一个非常简单的应用程序,其中包含一个由弹簧布局控制的内容窗格中的标签和文本字段。以下是相关代码:
public class SpringDemo1 {
public static void main(String[] args) {
...
Container contentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
contentPane.add(new JLabel("Label: "));
contentPane.add(new JTextField("Text field", 15));
...
frame.pack();
frame.setVisible(true);
}
}
单击“启动”按钮以使用Java™ Web Start运行 SpringDemo1(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
当 GUI 首次出现时,它看起来是这样的:
当调整大小使其变大时,它看起来是这样的:
显然,我们有一些问题。窗口不仅显示得太小,而且即使调整大小,组件仍然位于(0,0)处。这是因为我们没有设置任何弹簧来指定组件的位置和容器的宽度。一个小小的安慰是,至少组件都处于其首选大小 我们从SpringLayout
为每个组件创建的默认弹簧中免费获得了这一点。
我们的下一个示例,SpringDemo2.java
,通过为每个组件指定位置来改善情况。点击“启动”按钮以使用Java™ Web Start运行 SpringDemo2(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
在这个示例中,我们将指定组件应该在一行中显示,并且它们之间有 5 个像素的间距。以下代码指定了标签的位置:
//Adjust constraints for the label so it's at (5,5).
layout.putConstraint(SpringLayout.WEST, label,
5,
SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label,
5,
SpringLayout.NORTH, contentPane);
第一个putConstraint
调用指定标签的左(西)边缘应距其容器的左边缘 5 像素。这对应于 x 坐标为 5。第二个putConstraint
调用设置了标签的顶部(北)边缘与其容器之间的类似关系,导致 y 坐标为 5。
这是设置文本字段位置的代码:
//Adjust constraints for the text field so it's at
//(*<label's right edge>* + 5, 5).
layout.putConstraint(SpringLayout.WEST, textField,
5,
SpringLayout.EAST, label);
layout.putConstraint(SpringLayout.NORTH, textField,
5,
SpringLayout.NORTH, contentPane);
第一个putConstraint
调用使文本字段的左(西)边缘与标签的右(东)边缘相隔 5 像素。第二个putConstraint
调用与第一个片段中的第二个调用类似,并具有将组件的 y 坐标设置为 5 的相同效果。
前面的示例仍然存在容器显示得太小的问题。但是当我们调整窗口大小时,组件就位于正确位置了:
为了使容器最初以正确的大小显示,我们需要设置定义容器右(东)边和底部(南)边的弹簧。默认情况下,没有设置右边和底部容器边缘的约束。通过设置这些约束来定义容器的大小。SpringDemo3.java
展示了如何做到这一点。点击启动按钮使用Java™ Web Start来运行 SpringDemo3(下载 JDK 7 或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
这里是设置容器弹簧的代码:
layout.putConstraint(SpringLayout.EAST, contentPane,
5,
SpringLayout.EAST, textField);
layout.putConstraint(SpringLayout.SOUTH, contentPane,
5,
SpringLayout.SOUTH, textField);
第一个putConstraint
调用使容器的右边距离文本字段的右边缘向右移动 5 像素。第二个调用使其底边距离最高组件的底边超出 5 像素(为简单起见,我们假设是文本字段)。
最终,窗口以正确的大小显示:
当我们使窗口变大时,我们可以看到弹簧布局在起作用,将额外空间分配给可用的组件。
在这种情况下,弹簧布局选择将所有额外空间都分配给文本字段。虽然弹簧布局似乎对待标签和文本字段有所不同,但弹簧布局对任何 Swing 或 AWT 组件都没有特殊知识。它依赖于组件的最小、首选和最大大小属性的值。下一节将讨论弹簧布局如何使用这些属性,以及为什么它们可能导致空间分配不均匀。
弹簧和组件大小
SpringLayout
对象会自动为SpringLayout
控制的每个组件的高度和宽度安装Spring
。这些弹簧本质上是组件的getMinimumSize
、getPreferredSize
和getMaximumSize
方法的封装。通过“封装”我们的意思是这些弹簧不仅从这些方法中初始化适当的值,而且这些弹簧会跟踪这些值。例如,代表组件宽度的Spring
对象是一种特殊类型的弹簧,它简单地将其实现委托给组件的相关大小方法。这样,随着组件特性的变化,弹簧会与大小方法保持同步。
当组件的getMaximumSize
和getPreferredSize
方法返回相同的值时,SpringLayout
将其解释为组件不应该被拉伸。JLabel
和JButton
是以这种方式实现的组件的示例。因此,SpringDemo3 示例中的标签不会被拉伸。
一些组件的getMaximumSize
方法,如JTextField
,返回其最大尺寸的宽度和高度值为Integer.MAX_VALUE
,表示组件可以增长到任意大小。因此,当 SpringDemo3 窗口被放大时,SpringLayout
将所有额外空间分配给唯一可以增长的弹簧 决定文本字段大小的弹簧。
关于 SpringLayout API 的更多信息
SpringDemo 示例使用SpringLayout
方法putConstraint
来设置与每个组件关联的弹簧。putConstraint
方法是一个方便的方法,让您修改组件的约束而无需使用完整的弹簧布局 API。这里再次是从SpringDemo3
设置标签位置的代码:
layout.putConstraint(SpringLayout.WEST, label,
5,
SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label,
5,
SpringLayout.NORTH, contentPane);
这里是直接使用SpringLayout.Constraints
和Spring
类的等效代码:
SpringLayout.Constraints contentPaneCons =
layout.getConstraints(contentPane);
contentPaneCons.setX(Spring.sum(Spring.constant(5),
contentPaneCons
.getConstraint(SpringLayout.WEST)));
contentPaneCons.setY(Spring.sum(Spring.constant(5),
contentPaneCons
.getConstraint(SpringLayout.NORTH)));
要查看整个演示如何转换为使用此 API,请查看SpringDemo4.java
。该文件还包括一个更加精心制作(并且更长)的代码版本,用于设置容器的大小。点击“启动”按钮以使用Java™ Web Start运行 SpringDemo4(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
正如前面的片段所暗示的,SpringLayout
和SpringLayout.Constraints
倾向于使用不同的约定来描述弹簧。SpringLayout
API 使用边缘来定义其约束。弹簧连接边缘以建立它们之间的线性关系。边缘由组件使用以下常量定义:
-
SpringLayout.NORTH
指定组件边界矩形的顶边。 -
SpringLayout.SOUTH
指定组件边界矩形的底边。 -
SpringLayout.EAST
指定组件边界矩形的右边缘。 -
SpringLayout.WEST
指定组件边界矩形的左边缘。 -
SpringLayout.BASELINE
指定组件的基线。 -
SpringLayout.HORIZONTAL_CENTER
指定组件边界矩形的水平中心。 -
SpringLayout.VERTICAL_CENTER
指定组件边界矩形的垂直中心。
边与Spring
对象不同,SpringLayout.Constraints
类了解边,但仅对以下属性有Spring
对象:
-
x
-
y
-
width
-
height
每个Constraints
对象维护其弹簧与其代表的边之间的以下关系:
west = x
north = y
east = x + width
south = y + height
如果您感到困惑,不要担心。下一节介绍了一些实用方法,您可以使用这些方法来完成一些常见的布局任务,而无需了解弹簧布局 API 的任何内容。
网格的实用方法
因为SpringLayout
类是为 GUI 构建器创建的,为布局设置单独的弹簧可能会很麻烦。本节介绍了一些方法,您可以使用这些方法来安装布局一组组件所需的所有弹簧。这些方法模拟了GridLayout
、GridBagLayout
和BoxLayout
类的一些特性。
两个方法,称为makeGrid
和makeCompactGrid
,在SpringUtilities.java
中定义。这两种方法都通过将组件分组到行和列中,并使用Spring.max
方法来创建宽度或高度弹簧,使得行或列足够大以容纳其中的所有组件。在makeCompactGrid
方法中,相同的宽度或高度弹簧用于特定列或行中的所有组件。相比之下,在makeGrid
方法中,宽度和高度弹簧由容器中的每个组件共享,强制它们的大小都相同。此外,Spring
提供了用于创建不同类型弹簧的工厂方法,包括依赖于其他弹簧的弹簧。
让我们看看这些方法是如何运作的。我们的第一个示例,在源文件SpringGrid.java
中实现,显示了一堆数字在文本字段中。中心文本字段比其他字段宽得多。就像GridLayout
一样,有一个大单元格会强制所有单元格大小相等。点击启动按钮以使用Java™ Web Start运行 SpringGrid(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是在 SpringGrid 中创建和布局文本字段的代码:
JPanel panel = new JPanel(new SpringLayout());
for (int i = 0; i < 9; i++) {
JTextField textField = new JTextField(Integer.toString(i));
...*//when i==4, put long text in the text field*...
panel.add(textField);
}
...
SpringUtilities.makeGrid(panel,
3, 3, //rows, cols
5, 5, //initialX, initialY
5, 5);//xPad, yPad
现在让我们看一个示例,在源文件SpringCompactGrid.java
中,该示例使用makeCompactGrid
方法而不是makeGrid
。此示例显示了大量数字,以展示弹簧布局最小化所需空间的能力。点击“启动”按钮以使用Java™ Web Start运行 SpringCompactGrid(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是 SpringCompactGrid GUI 的外观:
这是创建并布局 SpringCompactGrid 中文本字段的代码:
JPanel panel = new JPanel(new SpringLayout());
int rows = 10;
int cols = 10;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int anInt = (int) Math.pow(r, c);
JTextField textField =
new JTextField(Integer.toString(anInt));
panel.add(textField);
}
}
//Lay out the panel.
SpringUtilities.makeCompactGrid(panel, //parent
rows, cols,
3, 3, //initX, initY
3, 3); //xPad, yPad
makeCompactGrid
方法最方便的用途之一是将标签与组件关联,其中标签位于一列,组件位于另一列。文件SpringForm.java
以这种方式使用makeCompactGrid
,如下图所示。
点击“启动”按钮以使用Java™ Web Start运行 SpringForm(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是创建并布局 SpringForm 中标签-文本字段对的代码:
String[] labels = {"Name: ", "Fax: ", "Email: ", "Address: "};
int numPairs = labels.length;
//Create and populate the panel.
JPanel p = new JPanel(new SpringLayout());
for (int i = 0; i < numPairs; i++) {
JLabel l = new JLabel(labels[i], JLabel.TRAILING);
p.add(l);
JTextField textField = new JTextField(10);
l.setLabelFor(textField);
p.add(textField);
}
//Lay out the panel.
SpringUtilities.makeCompactGrid(p,
numPairs, 2, //rows, cols
6, 6, //initX, initY
6, 6); //xPad, yPad
因为我们使用了真正的布局管理器而不是绝对定位,布局管理器会动态响应涉及组件的更改。例如,如果标签的名称是本地化的,弹簧布局会生成一个根据需要给第一列更多或更少空间的配置。正如下图所示,当窗口调整大小时,灵活大小的组件——文本字段——会占用所有多余空间,而标签则保持所需空间。
我们在SpringBox.java
中的makeCompactGrid
方法的最后一个示例显示了一些配置为在单行中布局的按钮。单击“启动”按钮以使用Java™ Web Start运行 SpringBox(下载 JDK 7 或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
请注意,在单行的情况下,行为几乎与BoxLayout
的行为相同。不仅组件的布局方式与BoxLayout
安排它们的方式相同,而且使用SpringLayout
的容器的最小、首选和最大尺寸返回与BoxLayout
相同的结果。这是产生此布局的makeCompactGrid
调用:
//Lay out the buttons in one row and as many columns
//as necessary, with 6 pixels of padding all around.
SpringUtilities.makeCompactGrid(contentPane, 1,
contentPane.getComponentCount(),
6, 6, 6, 6);
让我们看看当我们调整窗口大小时会发生什么。这是一个奇特的特殊情况,值得注意,因为在你的第一个布局中可能会意外遇到它。
什么都没动!这是因为没有定义任何组件(按钮)或它们之间的间距是可伸缩的。在这种情况下,弹簧布局计算出父容器的最大尺寸等于其首选尺寸,这意味着父容器本身不可伸缩。如果 AWT 拒绝调整大小不可伸缩的窗口可能会更少混淆,但它没有。布局管理器在这里无法做出任何明智的操作,因为没有组件会占用所需的空间。它不会崩溃,而是什么都不做,保持所有组件不变。
SpringLayout API
使用SpringLayout
的 API 分布在三个类中:
-
SpringLayout
-
SpringLayout.Constraints
-
Spring
SpringLayout
构造函数或方法 | 目的 |
---|---|
SpringLayout() | 创建一个SpringLayout 实例。 |
SpringLayout.Constraints getConstraints(Component) | 获取与指定组件关联的约束(弹簧集合)。 |
Spring getConstraint(String, Component) | 获取组件边缘的弹簧。第一个参数指定边缘,必须是以下SpringLayout 常量之一:NORTH 、SOUTH 、EAST 或WEST 。 |
void putConstraint(String, Component, int, String, Component) void putConstraint(String, Component, Spring, String, Component) | 定义两个组件边缘之间关系的便捷方法。前两个参数指定第一个组件及其受影响的边缘。后两个参数指定第二个组件及其受影响的边缘。第三个参数指定确定两者之间距离的 spring。当第三个参数为整数时,创建一个常量 spring 以提供组件边缘之间的固定距离。 |
SpringLayout.Constraints
构造函数或方法 | 目的 |
---|
| SpringLayout.Constraints() SpringLayout.Constraints(Spring, Spring) | 创建一个SpringLayout.Constraints
实例。 |
SpringLayout.Constraints(Spring, Spring, Spring, Spring) | 创建一个SpringLayout.Constraints
实例。前两个参数分别指定 X 和 Y springs,后两个参数分别指定高度和宽度 springs。省略参数会导致相应的 spring 为null
,SpringLayout
通常会用适当的默认值替换。 |
| Spring getConstraint(String) Spring getHeight() | 获取约束Spring
。获取高度Spring
。 |
Spring getWidth() | 获取宽度Spring
。 |
Spring getX() | 获取 X 坐标Spring
。 |
Spring getY() | 获取 Y 坐标Spring
。 |
void setConstraint(String, Spring) | 设置SpringLayout.Constraints
的约束。第一个参数指定 X spring,第二个参数指定 Y spring。 |
void setHeight(Spring) | 设置高度Spring
。 |
void setWidth(Spring) | 设置宽度Spring
。 |
void setY(Spring) | 获取或设置指定的弹簧。getConstraint
和 setConstraint
方法的字符串参数指定一个边缘名称,并且必须是 SpringLayout
常量 NORTH
、SOUTH
、EAST
或 WEST
中的一个。 |
Spring
方法 | 目的 |
---|---|
静态 Spring constant(int) 静态 Spring constant(int, int, int) | 创建一个不跟踪组件大小的弹簧。三参数版本创建一个弹簧,其最小值、首选值和最大值按指定顺序设置。一参数版本创建一个弹簧,其最小值、首选值和最大值都设置为指定整数。尽管名称是常量,但由 constant 返回的弹簧是可变的。为使布局正常工作,SpringLayout 可能被迫调整“常量”弹簧。因此,除非(1)您真正希望弹簧始终完全相同,并且(2)其他弹簧在布局中提供了一些灵活性,否则应避免重用常量弹簧。 |
| 静态 Spring sum(Spring, Spring) 静态 Spring max(Spring, Spring)
静态 Spring minus(Spring) | 创建一个经过某种数学操作的弹簧。sum
方法将两个弹簧相加。max
方法返回一个值始终大于或等于两个参数值的弹簧。minus
方法返回一个与参数方向相反的弹簧。minus
方法可用于创建 sum
方法的参数,从而获得两个弹簧之间的差异。 |
| int getMinimumValue() int getPreferredValue()
int getMaximumValue() | 从弹簧获取相应的值。对于由 SpringLayout
创建的自动跟踪组件的弹簧,这些方法会调用组件相应的 get*Xxx*Size
方法。 |
获取值() 设置值(int) | 获取或设置弹簧的当前值。 |
---|
使用 SpringLayout 的示例
以下表格列出了一些使用弹簧布局的示例。
示例 | 描述位置 | 注释 |
---|---|---|
SpringDemo3 |
本页 | 使用SpringLayout 创建一排均匀间隔、自然大小的组件。 |
SpringDemo4 |
本页 | 重新实现 SpringDemo3 以直接使用SpringLayout.Constraints 和Spring 。 |
SpringGrid |
本页 | 使用SpringLayout 和makeGrid 实用方法创建所有组件大小相同的布局。 |
SpringCompactGrid |
本页 | 使用SpringLayout 和makeCompactGrid 实用方法创建一种布局,其中一行中的所有组件具有相同的高度,一列中的所有组件具有相同的宽度。 |
SpringForm |
本页 | 使用SpringLayout 和makeCompactGrid 对齐标签-文本字段对。 |
SpringBox |
本页 | 使用SpringLayout 和makeCompactGrid 演示布局单行组件时,当没有弹簧可以增长时会发生什么。 |
SpinnerDemo |
如何使用微调器 | 使用SpringLayout 和makeCompactGrid 布局标签-微调器对的行。 |
TextInputDemo |
如何使用格式化文本字段 | 使用SpringLayout 和makeCompactGrid 布局标记组件的行。这些组件是文本字段、格式化文本字段和微调器的混合。 |