本章目标: 在第9章中,我们学习了许多用来构建GUI程序的部件,不过到现在为止,我们还无法让其“听话”的按照我们的意图摆放这些部件。在本章中,我们要学习如何进行部件的布局,也就是让部件能够“听话”地摆放在我们想放的位置上。我们将学会通过边框、网格、组合和GridBagLayout四种方式进行部件的布局管理。
10.1 边框布局 传授新知
我们回顾一下在第9章中,我们在程序中总是使用以下两条语句定义了一个容器: JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new FlowLayout()); 凭着我们现在所积累的阅读程序的功夫,应该能够很快地知道我们通过第一条语句创建了一个容器JPanel类的panel1。 而接下来,我们则调用了panel1.setLayout(new FlowLayout()),在上一章中,我们一直没有对它进行相应的分析。现在该是揭开它的面纱的时候了。 单词layout的中文意思是“布局”、“布置”,setLayout就是设置布局格式。也就是说,容器panel1的方法setLayout是用来设置布局格式的。那么,我们一直用的是什么模式呢?对,就是后面括号里的FlowLayout()。顾名思义,也就是流布局方式。这是一种顺其自然的方式:从左到右,一个个对象地摆放,摆不下,就摆到下一行。所以,我们就无法去控制它。 从本章开始,我们就要学习一种控制布局的方法。在Java语言中,提供了各种布局管理器,以便大家能够达到这一目的。 通常我们最常使用的布局管理器是:Border Layout(边框布局管理器),如下图所示,边框布局管理器将一个屏幕分成了五个部分:东、南、西、北、中。
![](https://i-blog.csdnimg.cn/blog_migrate/3191b9bd5368c161d5e4ca0afd5b39f2.png) 图10-1 边框布局管理示意图
如果要使用这种边框布局管理进行布局控制,我们必须先将“容器”设置为“边框布局控制模式”,具体来说,就是当调用setLayout方法为容器设置布局控制模式时,参数设置为BorderLayout。例如: JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); 然后,我们就可以在使用容器的add方法添加部件时,附加上位置参数,使得该部件显示在指定的位置上。位置参数分别是: BorderLayout.NORTH 位置为北 BorderLayout.SOUTH 位置为南 BorderLayout.EAST 位置为东 BorderLayout.WEST 位置为西 BorderLayout.NORTH 位置为中心
实例说明
下面,我们就来试一试,使用按钮排出五个方向!请创建一个testBorder.java,输入以下源程序: 源程序:useTextArea.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testBorder extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); JButton north=new JButton("North"); JButton south=new JButton("South"); JButton east=new JButton("East"); JButton west=new JButton("West"); JButton center=new JButton("Center");
panel1.add(north,BorderLayout.NORTH); panel1.add(south,BorderLayout.SOUTH); panel1.add(east,BorderLayout.EAST); panel1.add(west,BorderLayout.WEST); panel1.add(center,BorderLayout.CENTER); } }
然后,我们使用javac编译这个程序,然后编辑一个显示这个Java Applet的HTML页面。最后调用appletviewer来观察这个页面,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/1969d2a3658b55b0eda18ce643923bbd.png) 图10-2 程序testBorder.java的输出(1)
![](https://i-blog.csdnimg.cn/blog_migrate/362e62d50c8a1c084e4db8564d9c0d48.png) 图10-3 程序testBorder.java的输入(2)
为了试一下,如果并没有在每个位置都安排一个部件,那么会怎么样呢?我们修改一下程序,将panel1.add(west,BorderLayout.WEST);这一行注释掉(就是在前面加上“//”号),也就是不显示西边的按钮,看一下结果如何。正如上图(图10-3)所示,西边由于没有部件,因此“中”就朝西靠,“占领”了它的位置。 而同样的,如果没有了南边北边,正如下图(10-4)所示,其它部件就会占领其位置:
![](https://i-blog.csdnimg.cn/blog_migrate/55a0162f34d950aa45cd97b8acd5a6e6.png) 图10-4 程序testBorder.java的输出(3)
![](https://i-blog.csdnimg.cn/blog_migrate/3b8d3b8fc382ff828466bab5de0c2ccc.png) 图10-5 程序testBorder.java的输入(4)
而如果我们修改一下程序,让中间的按钮不显示的话,就会出现如图10-5的样子,中间的区域并未并占领,而是空在那里了!这是与其它位置不同的地方,大家一定要记住。
一些提示: 其实这很好理解,如果中间的那一块的位置被其它位置上的部件占领的话,就会使得分不清“东”、“南”、“西”、“北”了。倒成了“左上角”、“左下角”、“右上角”、“右下角”了。
自测练习 1) 使用____________位置参数,能够使一个部件位于容器的顶部。 a. Layout.TOP b. BorderLayout.TOP c. Layout.NORTH d. BorderLayout.NORTH 2) 使用____________位置参数,能够使一个部件位于容器的右边。 a. BorderLayout.WEST b. BorderLayout.RIGHT c. BorderLayout.EAST d. BorderLayout.NORTH 3) 如果在东面没有放置部件,其它位置都有放置部件,那么中间的部件将靠向______。 a.左边 b.上面 c.右边 d.下面 4) 在第9章中,我们使用的布局管理器是_____________。 a.杂乱管理器 b.流管理器 c.没有使用布局管理器 d.顺序布局管理器 5) 边框布局管理器将一个“容器”分成了__________个位置。 a.9个 b.3个 c.4个 d.5个 6) 编写一个程序,使其界面如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/43f0b248f46ab19bd9fcc0e5193387b7.png) 图10-6 练习题图(1)
而且,当我们扩大这个窗体的宽度时,OK按钮并不会出现在文本框之后,而是产生如下图之输出结果:
![](https://i-blog.csdnimg.cn/blog_migrate/aa2755d3f71cafc25ab9cb5fa79b1029.png) 图10-7 练习题图(2)
练习答案
1)d 在边框布局管理器中,顶部是北,所以选择BorderLayout.NORTH。 2)c 在边框布局管理器中,右边是东,所以选择BorderLayout.EAST。 3)c 东在右边,所以东边没有部件,其它部件就挤向右边,占领了右边。 4)b 虽然a、d从字面意义上特别象我们得到的结果,而c则从感觉上比较象,但这些都不是正确答案。这种布局管理器称为流管理器。 5)d 当然是“东”、“西”、“南”、“北”、“中”5个部分了! 6) 以下是一个程序实例:
源程序:lianxi10_1.java
import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_1 extends JApplet { Label comment; JTextField username; JButton buttonOK;
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new BorderLayout()); comment=new Label("Please enter you name:"); username=new JTextField(); buttonOK=new JButton("OK");
panel1.add(comment,BorderLayout.NORTH); panel1.add(username,BorderLayout.CENTER); panel1.add(buttonOK,BorderLayout.SOUTH); }
}
10.2 网格布局 实例说明 下面,我们来看一个新的程序!首先创建一个testGrid.java文件,并输入以下源程序: 源程序:testGrid.java
import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGrid extends JApplet { String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(3,3)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } }
然后,我们使用javac编译这个程序,然后编辑一个显示这个Java Applet的HTML页面。最后调用appletviewer来观察这个页面,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/a6e14163c0f1606b09aa8119a16d2e3e.png) 图10-8 程序testGrid.java的输出
传授新知
由于在本章中,我们主要是关心如何摆放各个部件,而不是如何构建一个程序。所以,正如本例中的按钮一下,这一章中的所有部件都是一个样子,没有任何作用。这样也使得程序尽可能地变短了,更易于大家阅读和理解程序。 下面,我们就一起来看一下上面的这个程序。 1) String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9"} 我想大家都能很轻松地读懂这条语句,我们在此定义了一个字符串数组buttonLabels,它有9个字符串成员,也就是我们后面定义的9个按钮的标签文本。 值得注意的是,大家一定要知道,buttonLabels[1]表示哪个字符串!如果您的答案是“No.1”的话,就错了!正确的答案是“No.2”,这是因为在数组中索引值是从0开始的,也就是说如果要使用“No.1”的话,应该使用buttonLabels[0]。这对更好地理解后面的程序十分重要,也是基本功之一。 2) JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(3,3)); 在这两行程序中,我们首先定义了一个容器部件panel1。然后调用setLayout方法设置布局管理器。这里我们使用了一个新的布局管理器:GridLayout,网格布局管理器。 我们注意到GridLayout的后面带了两个参数:3,3。这有什么用呢?我们一起来看一下GridLayout方法的定义: public GridLayout (int rows,int cols) 我们看一下这两个参数,首先它们都是int型—整型的。那么它们分别起到什么作用呢?我们还是采用顾名思义法吧!row的中文意思是行,col的中文意思是列,后面加上一个s,是这两个单词的复数形式。 好,我们现在串起来想一下,我们定义了一个网格布局,然后定了它的行、列数!这不就画出了这个网格了吗?如果我们在语句是使用GridLayout(5,5)的话,就会把整个容器分成25个单元,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/126a656d2d2819db810c6e31291518d3.png) 图10-9 GridLayout(5,5)
![](https://i-blog.csdnimg.cn/blog_migrate/70456c41ece198b7a8c5f1e3c033efc7.png) 图10-10 GridLayout(3,3)
而我们在程序中使用的是GridLayout(3,3),所以它就将整个容器分成了如上图所示的9个部分(图10-10)。
注意: 这种划分是一种逻辑上的,暗藏式的划分,而不会把格子给划出来。另外,我们这里举的两个例子行、列都相等,其实完全可以不等。
3) for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); 这是一个循环结构的程序。我们先看循环语句,循环的初值是“x=0”,继续执行循环的条件语句是“x<buttonLabels.length”,每做一次循环,执行“x++”。 buttonLabels.length就是用来请得字符串数组buttonLabels的长度!也就是这个字符串数组中有多少个字符串?我们知道,我们在该数组中定义了9个。 从程序中,我们可以获知,当x=buttonLabels.length时,循环就将结束,应为它不满足条件x<buttonLabels.length。那不是少了一个嘛! 别忘了,我们使用buttonLabels[0]表示第一个字符串,buttonLabels[1]表示第二个字符串……,那么最后一个字符串就应该是buttonLabels[buttonLabels.length-1]嘛。 在循环中,我们使用容器提供的add方法,将新定义的按钮部件添加进去。 有时,我们可能想获得象下图所示的布局效果!让各个部件之间存在一些间隙。使用Java的网格布局可以实现吗?
![](https://i-blog.csdnimg.cn/blog_migrate/3be20ac9496108c06221582699f607f6.png) 图10-11 有间隙的网格布局
我很高兴地回答你:“可以!”,我们可以使用GridLayout的另一种构造器方法(签名不同)来实现: public GridLayout (int rows,int cols,int hgap,int vgap) 在这个方法中,可以带上四个整型参数,前两个我们已经很熟悉了,行数与列数。后面则是两个新的参数。 第一个是hgap,其中gap的意思是间隙、空隙的意思,而h则是horizontal(水平)的第一个字母。也就是说,我们可以通过hgap参数设置横向的间隙。 第二个是vgap,v则是vertical(垂直)的第一个字母。也就是说,我们可以通过vgap参数设置纵向的间隙。
自测练习
1)_________________是网格布局管理器。 a.BorderLayout b.GridLayout c.ReseauLayout d.FlowLayout 利用以下代码回答问题2、3、4、5: 2)这个布局中有__________行? a.7行 b.5行 c.6行 d.8行 3)这个布局中有__________列? a.7行 b.5行 c.6行 d.8行 4)这个布局将容器分为_________个部分? a.48个 b.35个 c.30个 d.40个 5)第5个部件位于__________位置。 a.左上角 b.左下角 c.右上角 d.右下角 e.中间 6)根据以下界面,编写一个程序
![](https://i-blog.csdnimg.cn/blog_migrate/d574a5ffba0db3ab9509567081d599bc.png) 图10-12 练习题图 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ 7) 如果我们构建一个5*5的网格布局,但只在该容器中加入17个按钮,将会出现什么情况?请编写一个程序,来试一试效果。 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
练习答案
1)b 没什么好解释的,请大家记住! 2)a 第一个参数是行数,因此是7行。 3)b 第二个参数是列数,因此为5列。 4)b 7行5列,其7*5,35个部分嘛。 5)c 第5个部件是第一行的最后一个,当然在右上角嘛。 6)下面是一个实现的程序实例: 源程序:lianxi10_2.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_2 extends JApplet { String buttonLabels[]={"1","2","3","4","5","6","7", "8","9","*","0","#"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(4,3,10,10)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } }
7)下面是一个实现的程序实例: 源程序:lianxi10_3.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_3 extends JApplet { String buttonLabels[]={"No.1","No.2","No.3","No.4","No.5", "No.6","No.7","No.8","No.9","No.10","No.11","No.12", "No.13","No.14","No.15","No.16","No.17"};
public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(5,5)); for (int x=0; x<buttonLabels.length;x++) panel1.add(new JButton(buttonLabels[x])); } } 这个程序使用javac编译完后,编写一个包含这个类的HTML页面,再用appletviewer来观察发现运行结果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/6a0bb66c2311aab003ddb865af03c0ec.png) 图10-13 练习答案图
这个输出是不是令你感到十分意外,整个程序根本不按要求分成5列,所以我们从这里得到一个使用网格布局中要十二分注意的一点:“请别忘了将网格填满”。否则程序的输出将不可预料。
一些提示: 如果你真的没有那么多东西来“占领”网格的话,我建议你使用一个空标签来填补这个空白的网格,使得程序的输出如你所愿。使用空标签的方法很容易: panel1.add(new Label(“”)); 从这里,我们也看出了,我们学习过的流布局管理器、边框布局管理器,以及我们刚学习过的网格布局管理器都比较死板,不够高级。
10.3 组合布局 传授新知
正如我们在上一小节结束的时候说的一样,各种布局管理器都有自己的缺点,没有一种能够真正地完全满足我们编写GUI程序时的要求。 而在Java语言中,允许在容器中加入其他容器,这样每个容器可以根据自己的需要采用不同的布局管理器,组合成为一个我们所需要的GUI程序界面。这种方法,我们就称之为组合布局。
注意: 与流布局、边框布局、网格布局不同,组合布局并不是一个新的布局管理器,它是通过结合各种布局管理器的优点,将它们组合地应用在GUI程序界面的开发中。这是一种布局管理的方法。也可以说是一种GUI程序界面的开发技巧。 当我们设计GUI程序界面时,最好先在纸上把它画出来,然后“分块解决”。也就是将能够组合在一起的部件找出来,将它们放在一个容器里,并为它们选择合适的布局管理器。然后把这些容器摆放在一起,就解决了。 设计时还要考虑到窗体大小发生改变的时候,引起的部件形体变化。这方面,请你熟记几个设计技巧: 1) 对于那些要求扁平状的部件,我们应该将它放置在边框布局中的南面或北面; 2) 对于那些要求细高状的部件,我们应该将它放置在边框布局中的东面或西面; 3) 对于那些可以随着窗体改变大小部分,我们可以将它放置在边框布局的中间; 4) 如果我们要求部件保持大小相同,那么,我们就应该采用网格布局。 下面,我们就通过几个实际的例子,来让大家领会和掌握这种设计的思路与方法。
实例说明 我们首先创建一个testCombination.java文件,然后输入以下源程序: 源程序:testCombination.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testCombination1 extends JApplet { public void init() { Frame frame1=new Frame("testCombination1"); frame1.setLayout(new BorderLayout()); TextArea text1=new TextArea(); frame1.add(text1,BorderLayout.CENTER); JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridLayout(1,3,10,5)); panel1.add(new JButton("A")); panel1.add(new JButton("B")); panel1.add(new JButton("C")); frame1.add(panel1,BorderLayout.SOUTH); frame1.pack(); frame1.show(); } }
然后,我们使用javac编译这个程序,然后编辑一个显示这个Java Applet的HTML页面。最后调用appletviewer来观察这个页面,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/2585984c9c8b16ca2b9851c5454ab1fa.png) 图10-14 程序testCombination.java的输出
正如上图所示,程序的输出与以前不同,各个部件不是显示在Appletviewer程序框中,而是显示在另一个窗口中。 这是怎么回事呢?下面我们就一起来看一下这个程序!
传授新知
在以前的程序中,我们一直都是使用容器JPanel,面板。而我们在这个程序中引进了一个新的容器Frame。使用了这个容器后,就会新创建一个窗口。这也就是为什么程序的输出有这么大的变化的原因。 1) Frame frame1=new Frame("testCombination"); 这条语句,定义了一个Frame容器frame1,然后使用new操作符调用构造器方法,后面带的参数“testCombination”则是这个Frame的标题。
一些提示: 其实大家能Frame所体现出来的效果是很熟悉的,它等价于Windows中的窗体。而Frame的标题就是窗体的标题。
2) frame1.setLayout(new BorderLayout()); 与JPanel容器一样,我们可以调用setLayout方法来设置Frame的布局管理器。在这里,我们将Frame容器frame1的布局管理器设置成为边框布局管理器(也就是我们在10.1小节中学习过的布局管理器)。 3) frame1.add(text1,BorderLayout.CENTER); 紧接着,我们调用frame1的add方法,将文本区部件text1添加到frame1容器中来。注意我们设置了它的位置:BorderLayout.CENTER。 这是因为,我们希望这个文本区能够随着窗体的大小变化而变化。所以适合将其放在在中间位置。 4) panel1.setLayout(new GridLayout(1,3,10,5)); 我们又定义了一个JPanel容器panel1,并将其的布局管理器设置为网格布局管理器。并通过指定参数,使得整个panel1被分成1行3列,水平空隙为10的网格。 5) frame1.add(panel1,BorderLayout.SOUTH); 这是组合布局方法最重要的一步,我们将panel1这个容器,加入到了frame1这个容器中去了。并且指定了panel1这个容器在整个frame1中所占的位置:BorderLayout.SOUTH,也就是下边。这样,panel1中包含的三个按钮就会永远(不管窗体大小如何改变)呆在文本区的下边,而且三个按钮的大小会根据窗体大小的改变而改变。
一些提示: 这是因为,panel1中的按钮是用网格布局的。 6) frame1.pack(); frame1.show(); 与JPanel不一样,使用Frame容器,不能够直接显示了出来。我们必须调用Frame容器的show方法才能使得Frame显示出来。 而在使用show方法之前,我们还需要使用pack方法将Frame中的内容做一个整合。请记住这里的使用方法。
自测练习
1)___________不属于布局管理器。 a.边框布局 b.组合布局 c.流布局 d.网格布局 2)如果要使用组合布局,需将容器的布局管理设置为__________。 a.BorderLayout() b.GridLayout() c.CombinationLayout() d.以上都不对 请说明理由: ____________________________________________________________________ 3)对于同一个容器,可以使用多种布局管理方式?________ a.对 b.不对 4)对于同一种容器,可以使用多种布局管理方式?________ a.对 b.不对 5) 将一个容器panel1放到容器frame1中的方法是___________。 a.frame1.insert(panel1) b.frame1.add(panel1) c.frame1.addJPanel(panel1) d.frame1.insertJPanel(panel1) 6) 编写一个程序,模拟如下图所示的小键盘:
![](https://i-blog.csdnimg.cn/blog_migrate/428831311ae3d5b7420096f8cd85aeb9.png) 图10-15 练习题图 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
练习答案
1)b 组合布局是一种将多种布局管理器应用在一个程序中的方法,它不属于布局管理器。 2)d 组合布局是一种方法,所以无须指定布局管理器,想指定也无法指定。 3)b 在一个程序中,一个容器只能有一种布局管理。 4)a 对于同一种容器在不同的程序中,当然可以采用不同的布局管理。 5)b 与在Frame上添加一个部件一样,使用Frame的add方法就可以了。 6) 以下是一个程序实现的实例: 源程序:lianxi10_4.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_4 extends JApplet { public void init() { Frame framePad=new Frame("NumberPad"); framePad.setLayout(new BorderLayout()); JPanel panelTop=new JPanel(); panelTop.setLayout(new GridLayout(1,4,5,10)); panelTop.add(new JButton("Lock")); panelTop.add(new JButton("/")); panelTop.add(new JButton("*")); panelTop.add(new JButton("-")); framePad.add(panelTop,BorderLayout.NORTH);
JPanel panelMid=new JPanel(); panelMid.setLayout(new GridLayout(3,3,10,5)); for(int x=1;x<=9;x++) panelMid.add(new JButton(String.valueOf(x))); JPanel panelBot=new JPanel(); panelBot.setLayout(new BorderLayout()); panelBot.add(new JButton("0"),BorderLayout.CENTER); panelBot.add(new JButton("."),BorderLayout.EAST); JPanel panelNum=new JPanel(); panelNum.setLayout(new BorderLayout()); panelNum.add(panelMid,BorderLayout.CENTER); panelNum.add(panelBot,BorderLayout.SOUTH); framePad.add(panelNum,BorderLayout.CENTER);
JPanel panelRight=new JPanel(); panelRight.setLayout(new GridLayout(2,1,10,5)); panelRight.add(new JButton("+")); panelRight.add(new JButton(" ")); framePad.add(panelRight,BorderLayout.EAST); framePad.pack(); framePad.show(); } }
10.4 GridBag布局 实例说明 到现在为止,我们已经学习了边框布局、网格布局以及组合布局,现在大家试一试编写一个程序,使其显示如下图所示的界面:
![](https://i-blog.csdnimg.cn/blog_migrate/ce57675bf53f95dae1648182290b7b9a.png) 图10-16 挑战(1)
怎么样,挺有难度的吧!完成这个GUI得花很多心思去设计组合,十分讨厌,下面我们就使用一个新的布局管理器GridBagLayout来解决这种难题。 首先,输入以下源程序: 源程序:testGridBag.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGridBag extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); gbdc.fill=GridBagConstraints.BOTH; gbdc.weightx=1; gbdc.weighty=1; panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); panel1.add(new JButton("No.3"),gbdc); gbdc.gridwidth=2; gbdc.gridx=0; panel1.add(new JButton("No.4"),gbdc); gbdc.gridx=2; gbdc.gridwidth=1; gbdc.gridheight=2; panel1.add(new JButton("No.5"),gbdc); gbdc.gridx=0; gbdc.gridheight=1; panel1.add(new JButton("No.6"),gbdc); gbdc.gridx=1; panel1.add(new JButton("No.7"),gbdc);
gbdc.gridx=0; gbdc.gridwidth=2; panel1.add(new JButton("No.8"),gbdc); gbdc.gridx=2; gbdc.gridwidth=1; panel1.add(new JButton("No.9"),gbdc); } }
传授新知
在这个程序中,我们使用了GridBagLayout轻松地完成了这个界面的设计,允分凸现出它的强大。可以这么说,GridBagLayout是Java语言中最强大的布局管理器。 GridBagLayout,从名字上看,就知道它与GridLayout有一定的渊源,是的,GridBagLayout的确与其十分类似,也是使用网格来进行布局管理的。但与GridLayout(网格布局)不同的是,GridBagLayout不像网格布局一相,需要所有的部件的大小、形状相同。而且还可以将某一个部件放在一个固定的位置上。 下面,我们一起来分析一下testGridBag.java程序。 1) panel1.setLayout(new GridBagLayout()); 在调用setLayout方法时,指定为GridBagLaoyout,使panel1使用GridBag布局管理。 2) GridBagConstraints gbdc=new GridBagConstraints(); GridBagLayout布局管理器是通过一个GridBagConstraints类来实现神奇的效果的。所以,我们要在使用时先定义一个GridBagConstraints类的对象。在这个程序中,我们定义了一个GridBagConstraints类的对象gbdc。 3) gbdc.fill=GridBagConstraints.BOTH; 由于网格单元可能比该单元中的部件大,如果是这样,部件放置在单元格内会有一些多余空间。在默认情况下,部件不会扩张,也就是不会填充这个多余空间。 GridBagConstraints提供了一个fill属性,我们可以通过设置它的值来起到不同的效果。 ¨ GridBagConstraints.NONE:不扩张,是默认值; ¨ GridBagConstraints.HORIZONTAL:部件水平扩张,将水平方向的多余空间填满; ¨ GridBagConstraints.VERTICAL:部件垂直扩张,将垂直方向的多余空间填满; ¨ GridBagConstraints.BOTH:部件同时向两个方向扩张,将单元格填满。 4) gbdc.weightx=1; gbdc.weighty=1; weightx和weighty是GridBagConstraints提供的另一对属性。它的取值是整型数,默认值为0。用来设置行(weightx)、列(weighty)的“重量”,如果值为0的话,所有的部件都会紧收在一起,聚集在中央,如图10-17所示。 而如果取值为其它数字,则会根据值来分配空间。 5) panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); panel1.add(new JButton("No.3"),gbdc); 在没有任何约束的时候,向gbdc中添加按钮,这时效果与采用网格布局的效果完全一样。一个接着一个地“占领”单元格。
![](https://i-blog.csdnimg.cn/blog_migrate/a74f329638be256e4743223954392d6d.png) 图10-17 当weightx与weighty为0时的效果图
6) gbdc.gridwidth=2; gbdc.gridx=0; panel1.add(new JButton("No.4"),gbdc); 由于第四个按钮(No.4)是宽度是2,在GridBagLayout中,是由gridwidth属性来控制添加进入的部件的宽度的。 我们通过gbdc.gridwidth=2将其设置为2,这样,再添加进入的部件就会变成为2个单元格的宽度。 另外,我们再使用gbdc.gridx=0让其另起一行,从最左边的单元格开始填充。 因此,我们发现第四个按钮被加在了第二行,宽度为2个单元格。
7) gbdc.gridx=2; gbdc.gridwidth=1; gbdc.gridheight=2; panel1.add(new JButton("No.5"),gbdc); 接下来,我们要摆放第五个按钮,这个按钮将从第3个单元开始填充,其宽度为一个单元格,而高度则为两个单元格。 因此,我们首先使用用gbdc.gridx=2,使得下一个添加的部件(第五个按钮)放入第3个单元格(0代表第1个单元格,因此第3个单元格应该是2)。 由于,前面我们已经将gridwidth设置为2了,因此,我们需要使用gbdc.gridwidth=1,将其值设置回1。 最后使用gdbc.gridheight=2,使得添入的部件的单元格纵向跨越两个单元格。
8) gbdc.gridx=0; gbdc.gridheight=1; panel1.add(new JButton("No.6"),gbdc); 我想这一段程序,大家应该都不会再有什么理解上的问题了吧!主要提醒大家注意的是,我们使用gbdc.gridheight=1将单元格纵向跨度改成了默认值1。这是因为我们在前面需要时将其改成了2,所以在此需要将其改回来。
实例说明 为了更好地理解这个强大的GridBagLayout布局管理器,我们再来做一个有趣的实验。首先,我们创建一个testGridBag2.java 源程序:testGridBag2.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class testGridBag2 extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); setSize(300,200); } } 运行这个程序,我们将得到以下结果:
![](https://i-blog.csdnimg.cn/blog_migrate/fce2d44be14084e3fa62662508081411.png) 图10-18 实验结果(1)
然后我们使用鼠标改变一下窗口的大小,看一下,这两个按钮有什么变化?你会惊奇地发现,窗口改变了大小,两个按钮的大小却没有变,而且一直呆在正中央的位置。
一些说明: 在这个程序中,我们使用了一个以前没有用过的语句:setsize(300.200),它的功能是在程序中设置窗口的大小。
现在我们对这个程序做一些修改!将添加两个按钮的两条语句: panel1.add(new JButton("No.1"),gbdc); panel1.add(new JButton("No.2"),gbdc); 将它们扩展为: gbdc.weightx=1; panel1.add(new JButton("No.1"),gbdc); gbdc.weightx=3; panel1.add(new JButton("No.2"),gbdc); 再重新编译、运行这个程序,你想会发生什么变化呢?我们一起来看一下结果:
![](https://i-blog.csdnimg.cn/blog_migrate/637875eb2127fd4363ee5ebeed12ef38.png) 图10-19 实验结果(2) 为什么会得到这个效果呢?我们在程序中添加按钮的程序段前加入一句: gbdc.fill=GridBagConstraints.HORIZONTAL; 再重新编译一下程序,再看看程序的输出有什么变化! 在得到结果之前,自己可以想象一下结果,然后看一下程序的实际输出与你的想法是否相吻合。 我们惊奇地发现,第二个按钮,突然变得十分宽起来(如图10-20所示)。这是因为放置第二个按钮的单元格的宽度是3,而第一个按钮的宽度是1。而且,我们又让第二个按钮横向扩展,因此得到了这样的输出结果。
![](https://i-blog.csdnimg.cn/blog_migrate/892862138bd8372a53161f582b75e0e6.png) 图10-20 程序实验结果(3)
相信实验做到这里,不须我说,大家也会有一些心得体会了。但是GridBagLayout远不止这一点,大家应该多做试验,才能够在真实的使用环境中有效地掌握GridBagLayout。
自测练习
1) 如果不设置,GridBagConstraints的fill属性的值是_________。 a.GridBagConstraints.VERTICAL b.GridBagConstraints. HORIZONTAL c.GridBagConstraints.BOTH d.GridBagConstraints.NONE 2) GridBagConstraints的weightx和weighty的值是_______和_______。 a. 1 0 b.0 0 c.0 1 d.1 1 3) 如果在程序中,我们将gridx设置为0,则______________。 a.新的部件从新的一行开始添加 b.新的部件将覆盖掉第一个部件 4) 编写一个程序,使用GridBagLayout布局管理器实现对小键盘的模拟。程序的输出如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/44b5756b6935f56f62fd28f8d35564ab.png) 图10-21 练习题图 ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________ ____________________________________________________________________
练习答案
1)d GridBagConstraints属性fill的默认值是GridBagConstraints.NONE。 2)b 这两个值的默认值均是0。 3)a 当然不会覆盖已经存在的部件了。 4)以下是一个程序实例: 源程序:lianxi10_5.java import java.awt.*; import javax.swing.*; import java.applet.Applet;
public class lianxi10_5 extends JApplet { public void init() { JPanel panel1=(JPanel)getContentPane(); panel1.setLayout(new GridBagLayout()); GridBagConstraints gbdc=new GridBagConstraints(); gbdc.fill=GridBagConstraints.BOTH; gbdc.weightx=1; gbdc.weighty=1; panel1.add(new JButton(" "),gbdc); panel1.add(new JButton("/"),gbdc); panel1.add(new JButton("*"),gbdc); panel1.add(new JButton("-"),gbdc);
gbdc.gridx=0; panel1.add(new JButton("7"),gbdc); gbdc.gridx=1; panel1.add(new JButton("8"),gbdc); gbdc.gridx=2; panel1.add(new JButton("9"),gbdc); gbdc.gridheight=2; gbdc.gridx=3; panel1.add(ne |