1. GridLayout——网格布局:
1) 网格顾名思义就是纵横分割大小一样的格网,每个格子都是矩形的,且大小相等,每个格子只能存放一个组件;
2) 构造器:最大的特点就是必须指定格网是几行几列的
i. 指定行列:GridLayout(int rows, int cols);
ii. 同时指定格子之间的间距:GridLayout(int rows, int cols, int hgap, int vgap);
3) 格子的先后次序是从左到右、从上到下,默认添加组件的次序就是这样的,但不过和流式布局有一定的区别,那就是网格布局组件的大小是由网格大小决定的,组件会被调整到刚好填充满整个网格,是先有网格再有组件大小,流式正好相反;
4) 示例:桌面计算器的面板可以用网格布局
public class AwtTest { public static void main(String[] args) { // TODO Auto-generated method stub Frame f = new Frame("GridLayout Test"); // 默认BorderLayout f.add(new TextField(30), BorderLayout.NORTH); Panel p = new Panel(); p.setLayout(new GridLayout(3, 5, 4, 4)); String[] btn = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "."}; for (int i = 0; i < btn.length; i++) { p.add(new Button(btn[i])); } f.add(p); // 默认添加到CENTER f.pack(); f.setVisible(true); } }
2. GridBagLayout——网格袋布局:
1) 是GridLayout的升级,更加灵活,允许网格大小互不相同(一个格子可以纵向或横向跨越多个格子的长度),当窗口伸缩时里面的组件也会跟着一起精确地伸缩;
2) 构造器只有一种,即默认的无参构造器:GridBagLayout();
!!如何精确地控制布局必须同一个一个结构体GridBagConstraints来控制;
3) 布局规则:即一个GridBagLayout布局管理器一次只能根据一个GridBagConstraints约束条件来约束一个组件的行为,下面将介绍如何在网格袋布局下插入一个组件
i. 先创建约束器,调用GridBagConstraints类的构造器,一般直接使用其默认的无参构造器即可:GridBagConstraints(); // GridBagConstraints gbc = new GridBagConstraints();
ii. 设置约束器的各个参数:gbc.gridx = ??; gbc.fill = ??; ...
!!其实约束器有另一个版本的构造器,那就是包含所有参数的构造器使用非常不便,必须传递所有的参数,而实际往往只对其中一些参数感兴趣而不必设置所有参数,因此通常调用无参构造器,构造出的对象的各个参数都采用默认值,需要修改那个参数再具体修改;
iii. 将布局管理器跟约束条件和带插入的组件绑定在一起,这里需要使用GridBagLayout类的setConstraints方法:void setConstraints(Component comp, GridBagConstraints constraints);
!!例如:gbl.setConstraints(c, gbc); // 这里就是将布局管理器gbl和带插入的组件c以及约束规则gbc绑定在一起了
iv. 最后将约束过的组件c添加到窗口中即可:f.add(c);
!!由于约束同时只能对一个组件有效,因此要添加另一个组件就必须要重新重复上述步骤,其中gbc不需要重新创建,只需要修改gbc的参数然后再作用于另一个组件就行了;
4) 约束规则:都是GridBagConstraints的域,常用的有如下(里面提到的所有静态常量都属于GridBagConstraints)
》》》》普通约束规则
i. int gridx, gridy:组件插入到哪个网格中,这是网格的坐标索引,比如(3, 4)就带表横向第3个纵向第4个网格,add时组件就放到该网格中,左上角其实坐标是(0, 0);
!!也可以使用常量RELATIVE,表示紧跟在上一个add的组件之后,比如上一个组件坐标是(4, 5),如果这两个域设为(RELATIVE, 7)那么实际将add到(4+1, 7)的位置,如果为(RELATIVE, RELATIVE)则实际add到(4+1, 5+1)的位置,即紧跟其后,位置+1;
!!默认值就是(RELATIVE, RELATIVE);
ii. int gridwidth, gridheight:组件横向和纵向分别跨越多少个网格,默认值是(1, 1),就跟正常的GridLayout一样了,当然可以传递特殊值(静态常量)
a. REMAINDER:表示这是横向(或纵向)的最后一个组件
!!注意:GridBagLayout的构造器并没有指定格网是几乘几的,因此如果不做任何约束那么默认就跟流式一样从左往右从上到下一直排下去,因此必须要用REMAINDER来控制换行,当gridwidth = REMAINDER时就表示这是横向最后一个组件,那么下一个组件就会add在下一行的开头了;
!!一般纵向REMAINDER很少用到;
b. RELATIVE:和gridx和gridy不同,是指该组件是横向(或纵向)的倒数第二个组件,这在纵向的应用就较多了;
》》》》伸缩约束规则(是指在窗口被伸缩时组件如何跟着自动伸缩)
i. int fill:规定组件如何占据空白区域,比如窗口拉伸后如果组件保持原样不动那么就会多出空白区域,现在就是规定组件跟着窗口一块儿伸缩时如何占据这些空白区域,有如下选择:
NONE:组件不动,不占空白区域
HORIZONTAL:组件可以水平方向上伸缩
VERTICAL:垂直伸缩
BOTH:双向伸缩
ii. int weightx, weighty:组件在横向和纵向上如何按比例伸缩,一般一个方向上会有很多组件,那么在窗口伸缩时就会遇到一个问题,各个组件的伸缩比例应该如何。这两个参数就规定了同一方向上的伸缩比例,比如横向上三个组件的weightx值分别是13, 9, 33,那么在窗口拉伸时这三个组件拉伸的比例就是13:9:33,其中第三个拉伸的幅度最大,缩小时也是一样的,而weighty是纵向的;
!!fill、weightx、weighty必须对应指定,否则会发生异常,比如fill指定了水平伸缩,那么weightx就必须不为0(weight的默认值是0,表示不伸缩),否则两个相互矛盾引发异常;
》》》》组件尺寸约束规则
!!这里首先要了解在格网中各种跟尺寸有关的概念:
a. 组件最小尺寸:包含组件关键信息的最小区域,比如一个按钮中的文字所包围的区域就是组件的最小区域,因为其中的文字使其关键信息;
b. 组件尺寸和内部填充区域:是指组件的边框所包围的区域,比如一个按钮(边框)可以很大,但里面的文字很小,里面文字包含的区域就是组件最小尺寸,而文字和按钮边框之间还存在很多空白区域,该区域就是内部填充区域;
c. 组件显示区域以及外部填充区域:就是指存放组件的网格,比如将一个按钮放入一个网格,网格可以很大,按钮可以很小,可以将按钮显示在网格的左上角、右上角(网格中的任意一个位置都行),而组件和显示区域之间的空白区域就是外部填充区域;
d. 小结:显示区域 ≥ 组件尺寸 ≥ 组件最小尺寸
!!接下来就是尺寸约束规则了:
i. int ipadx, ipady:即inner padding x and y,即组件的内部填充尺寸,组件尺寸等于组件最小尺寸+2ipadx(ipady);
ii. Insets insets:规定了外部填充区域的大小,实际指定了组件实施区域的边间直接的距离
iii. anchor:组件在显示区域中的位置,总共有9个方位,分别是东南西北中、东北、西北、东南、西南,英文就不枚举了,比如南是SOUTH,东北是NORTHEAST,其它类推;
5) 示例:第一行4个按钮,第二行2个按钮,第三行两个按钮其中第二个按钮分为上下两个按钮
public class AwtTest { private Frame f = new Frame("GridBagLayout Test"); private GridBagLayout gbl = new GridBagLayout(); private GridBagConstraints gbc = new GridBagConstraints(); private Button[] btns = new Button[10]; private void addButton(Button btn) { gbl.setConstraints(btn, gbc); f.add(btn); } public void init() { for (int i = 0; i < 10; i++) { // 先初始化10个按钮 btns[i] = new Button("button" + i); } f.setLayout(gbl); // 设定框架的布局模式 gbc.fill = GridBagConstraints.BOTH; // 伸缩首先规定是两个方向上的 gbc.weighty = 1; // 纵向比例都是1:1 // 第1行的4个按钮 gbc.weightx = 1; // 第一行的三个都是1:1:1 addButton(btns[0]); addButton(btns[1]); addButton(btns[2]); gbc.gridwidth = GridBagConstraints.REMAINDER; // 第4个添加后就要换行了 addButton(btns[3]); // 第2行1个按钮,仍然保持REMAINDER换行状态 addButton(btns[4]); // 第3行2个按钮,分别横跨2格 gbc.gridwidth = 2; gbc.weightx = 1; addButton(btns[5]); gbc.gridwidth = GridBagConstraints.REMAINDER; addButton(btns[6]); // 7纵跨2个格子,8、9一上一下 gbc.gridheight = 2; gbc.gridwidth = 1; gbc.weightx = 1; addButton(btns[7]); // 由于纵跨2格因此纵向伸缩比例不需要调整,默认为1*2格,比例刚好 gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridheight = 1; gbc.weightx = 3; addButton(btns[8]); addButton(btns[9]); f.pack(); f.setVisible(true); } public static void main(String[] args) { new AwtTest().init(); } }!!可以尝试把4的weightx设成0,8和9的weighty设成0,发现仍然可以按比例伸缩,那是因为4伴随上一行,8和9伴随左边的7,因此一旦fill里设定了一个方向的伸缩,那么实际不管weight怎么设定都会强行伸缩的;