Java 布局管理器不完全指南
绝大多数的Java程序员都不太热衷于写Java桌面应用程序,他们都觉得用Java写界面既丑,速度又慢,而且很复杂。许多人认为,Java写不了好的桌面程序。好多初学Java的人,在刚学会Java语法之后,直接跳过桌面程序,成为了JavaEE程序员
确实,对于VB或者VC来说,用Java写桌面程序难度差的不是一个数量级。Java语言,本来就不适合快速开发,对于Java大部分的开发框架,本不是针对快速开发而言,而是为了更好的扩展与重构。
个人认为,Swing的难点在于复杂的布局管理器。只要吃透了这个,写Java桌面程序就简单了。
1.流式布局 (FlowLayout)
这是面板(JPanel)的默认布局管理器。流式布局管理器的特点是在一行上水平排列组件,直到没有足够的空间为止,这时开始新的一行。当用户缩放容器时,布局管理器自动地调整组件的位置使其填充可用的空间。
FlowLayout有三种构造方法,
- FlowLayout() : 使用居中的对齐方式,组件间水平和垂直间距都为5。
- FlowLayout(int align) : align表示对齐方式,可以是LEFT,CENTER或RIGHT。
- FlowLayout(int align, int hgap, int vgap) : hgap 水平间距,vgap 垂直间距。
2.边界布局 (BorderLayout)
这是每个JFrame的内容窗格的默认布局管理器( JFrame.getContentPane() ).
边界布局管理器把组件分成5个区域,NORTH,SOUTH,EAST,WEST,CENTER。先放入边缘组件,当容器缩放的时候,边缘组件不会改变,而中部组件的大小会发生相应变化。
但是BorderLayout有一个问题,就是当添加多个组件到一个区域时,只显示最新添加的组件,而且组件会充满整个区域。解决的方法是在区域上添加一个面板(JPanel),在面板上放置多个组件。
3.箱式布局 (BoxLayout)
要想创建一个使用箱式布局的新容器,可以调用:
Box b = Box.createHorizontalBox();
或者
Box b = Box.createVerticalBox();
下面是添加组件的常用方法:
b.add(okButton); b.add(cancelButtn);
在水平的箱子里,组件从左到右排列.在垂直的箱子里,组件从上到下排列。
下面详细的研究一下水平布局。
每个组件有三个尺寸,首选尺寸,最大尺寸,最小尺寸。
下面是箱式布局管理器的工作细节:
- 计算最高组件的最大高度。
- 尝试把所有的组件在垂直方向上增至这个高度。
- 如果一个组件没有增至这个高度,那么它的y对齐方式要通过调用getAlignmentY()方法获得。这个方法将返回一个介于0(顶端对齐)到1(底端对齐)之间的浮点数,组件的默认值是0.5。
- 获得每个组件的首选宽度,然后把所有首选宽度累加起来。
- 如果所有的首选宽度的总和小于箱的宽度,那么组件的宽度就会延伸到不超过最大宽度的值,直到适应箱的宽度为止。组件从左到右依次排列,并且相邻的组件之间没有空间。如果所有的首选宽度的总和大于箱的宽度,组件就会被压缩,但不会小于各自的最小宽度,直到适应箱子的宽度为止。如果组件的最小宽度之和大于箱的宽度,有些组件就会显示不出来。
默认情况下,箱式布局各组件是没有间距的。如果需要添加间距,可以添加不可见的填充件。有这样三种填充件:支柱,固定区,胶水。
b.add(label) b.add(Box.createHorizontalStrut(10)); b.add(textField);
固定区填充件有点像一对支柱。例如:
b.add(Box.createRightArea(new Dimension(5,20)));
将添加一个宽度为5像素,高度是20像素的不可见区域。
胶水将组件互相拉开,直至充满整个空间。例如
b.add(button1); b.add(Box.createGlue()); b.add(button2);
如果这个箱子不包含其他的组件,那么button1就会被放在最左边,button2就会被放置到最右边。
4.网格组布局 (GridBagLayout)
网格组布局是所有布局管理器之首。可以认为网格组布局是没有限制的网格布局。在网格组布局中,行和列的尺寸都可以改变。可以通过将响铃的单元合并来适应更大的组件。使用网格组布局可能相当复杂,但是它最灵活且使用范围最广。
要想使用网格组布局管理器进行布局,必须经过下列过程:
- 建立GridBagLayout类型的对象。不需要指定网格的行数和列数,布局管理器会根据后面所给的信息猜测出来。
- 把GridBagLayout对象设置成组件的布局管理器。
- 为每个组件建立一个GridBagConstraints类型的对象。设置GridBagConstraints对象的域值以便制定组件在网格组中的布局方案。
- 最后通过下面的调用添加组件的约束。
add(component,constrants);
示例代码:
JPanel panel = new JPanel(); JLabel label = new JLabel("Test"); GridBagLayout layout = new GridBagLayout(); panel.setLayout(layout); GridBagConstraints constrants = new GridBagConstraints(); constrants.weightx = 100; constrants.weighty = 100; constrants.gridx = 0; constrants.gridy = 2; constrants.gridwidth = 2; constrants.gridheight = 1; panel.add(label, constrants);
知道如何设置GridBagConstraints对象的状态是很重要的,下面详细介绍GridBagConstraints的约束属性。
1.gridxgridy,gridwidth,gridheight
gridx,gridy表示组件在网格中的行列位置(第N行,第N列,从0开始计算)。gridwidth,gridheight表示组件所占的网格的行数和列数。示例代码中constrants应用的组件在第0行,第2列,横向占用2格,纵向占用1格。
2.weightx,weighty
增量字段,如果增量字段设置为0,这个区域永远是初始尺寸。默认增量字段的值为1,代表等比例拉伸组件大小。
3.fill
表示组件填充当前网格的属性。它有四个有效值,NONE,HORIZONTAL,VERTICAL,BOTH (为GridBagConstraints的static final成员变量),分表代表:不填充,横向填充,纵向填充,填充整个区域。
4.anchor
表示当组件在当前网格区域中的位置。有效值可以设置为CENTER,NORTH,SOUTH,NORTHEAST,EAST等。仅当组件没有充满整个区域时有效。
5.insets
表示外部填塞,用来设置组件周围增加的空白区域。通过设置Insets对象的left,right,top,button值在设置组件周围的空间量。
6.ipadx,ipady
表示内部填塞,该参数用以设置组件的最小尺寸。如果参数值为正值则组件的最小尺寸将比原始最小尺寸大,如果为负值,则组件的最小尺寸将会变得比原始的最小尺寸小。该参数也可以理解为直接为组件指定大小,这个设置的大小就是组件的最小尺寸。其设置后组件的大小为组件的原始最小尺寸加上ipadx(y)*2个像素。
对于GridBagLayout对象来说,本身也有columnWidths,rowHeights,columnWidths,rowWeights这四个属性。
1.columnWidths,rowHeights 设置一个int数组对象来表示各个网格的长度和宽度。例如
gbl.columnWidths = new int[] { 30, 80, 80, 80, 30 }; gbl.rowHeights = new int[] { 45, 200, 30, 45 };
表示网格中的前四列宽度为30,80,80,80,30,前四行宽度为45,200,30,45。
2.columnWeights,rowWeights 设置一个double数组对象来表示各个网格的长度和宽度的权重。当面板被拉伸时,会根据权重拉伸相对应的网格。权重为0表示不拉伸网格。为1表示等比例拉伸。
个人认为这个属性和GridBagConstraints中的weightx,weighty是一个意思,只是一个针对面板上的所有组件,一个针对相应组件而已。不过在实际的设计中,个人比较倾向于使用columnWeights, rowWeights而不是weightx,weighty。因为这样更全局,也更直观。
在使用GridBagLayout布局时,最好使用GridBagContraints帮助类(GBC)代替GridBagContraints类.这样会使得代码更加易读而且便于调试。
public class GBC extends GridBagConstraints { private static final long serialVersionUID = 2242355893259876283L; public GBC(int gridx, int gridy) { this.gridx = gridx; this.gridy = gridy; } public GBC(int gridx, int gridy, int gridwidth, int gridheight) { this.gridx = gridx; this.gridy = gridy; this.gridwidth = gridwidth; this.gridheight = gridheight; } public GBC setAnchor(int anchor) { this.anchor = anchor; return this; } public GBC setFill(int fill) { this.fill = fill; return this; } public GBC setWeight(double weightx, double weighty) { this.weightx = weightx; this.weighty = weighty; return this; } public GBC setInsets(int distance) { this.insets = new Insets(distance, distance, distance, distance); return this; } public GBC setIpad(int ipadx, int ipady) { this.ipadx = ipadx; this.ipady = ipady; return this; } }
下面是帮助类的使用方法
panel.add(label,new GBC(0,2,2,1).setFill(GBC.BOTH).setInsets(1));
注:本文参考《Java2核心技术卷一:基础知识》部分内容。