
模块十 建立GUIs 1
1. 抽象窗口工具包(AWT) 2
2. 第三节 建立图形用户界面 3
2.1. 容器 3
2.2. 定位组件 3
2.3. 组件大小 3
3. 框架(Frames) 3
4. Panels 4
5. 容器布局(Container Layout) 5
5.1. 布局管理器 5
5.2. FlowLayout的一个简单例子 6
6. 布局管理器 7
6.1. FlowLayout 7
6.2. BorderLayout 9
6.3. GridLayout 10
6.4. CardLayout 12
6.5. GridBag 14
7. 创建面板及复杂布局 14
8. 练习:建立Java GUIs 15
8.1. 创建计算器GUI 15
8.2. 创建帐目GUI 16
8.3. 检查进步情况 16
本模块为你介绍:使用AWT (抽象视窗工具包----建立GUIs的类包) 建立图形用户界面及其布局。
完成本模块学习时,你应该能够:
-描述AWT包及其组件
-描述Container、Component及Layout Manager等术语,以及它们如何在一起建立GUI
-使用Layout Manager
-使用Flow、Border、Gird及Card布局管理器来获得期望的动态布局
-增加组件到Container
-正确运用Frame及Panel容器
-描述如何使用嵌套容器来完成复杂的布局
-在Java软件程序中,标识如下内容:
-容器
-相关布局管理器
-所有组件的布局层次
1. 抽象窗口工具包(AWT)
AWT提供Java 小应用程序(applets)及应用程序中使用的基本GUI组件。AWT为应用提供于机器的接口,这将保证基于AWT的软件具有跨平台可移植的能力。
在学AWT之前,简单回顾一下对象层次结构:超类是可以扩展的,它们的属性是可继承的。而且,类可以是抽象的,也就是说,它们是子类的模板,子类可以具体实现它们。
java.awt包中包含了生成GUI组件的类。该包的基本情况如下图所示。
显示在屏幕上的每个GUI组件都是抽象类Component或MenuComponent的子类。也就是说,每个基本的组件都从Component类中继承了方法和实例变量。同样,菜单组件继承了MenuComponent类的方法和实例变量。
Container(容器)是Component的一个抽象子类,它允许其它的组件嵌套在里面。这些组件也可以是允许其它组件嵌套在里面的容器,于是就创建了一个完整的层次结构。在屏幕上布置GUI组件,容器是很有用的。Panel是Container的最简单的子类。Container的另一个子类是Window。
2. 建立图形用户界面
2.1. 容器
GUI组件需要使用add方法加入到容器中。容器有两个主要类型:Window和Panel
Window是显示屏上的本机窗口,它于其它容器。
Window有两种形式:Frame(框架)和Dialog(对话框)。Frame是一个带有标题和缩放角的窗口。对话框没有菜单条。尽管它能移动,但它不能缩放。
Panel包含在另一个容器中,或是在Web浏览器的窗口中。Panel确定一个四边形,其它组件可以放入其中。Panel必须放在Window之中(或Window的子类中)以便能显示出来。
2.2. 定位组件
容器里的组件的位置和大小是由布局管理器决定的。容器保持布局管理器的一个特定实例的引用。当容器需要定位一个组件时,它将调用布局管理器来做。当决定一个组件的大小时,同样如此。布局管理器完全控制容器内的所有组件。它负责计算并定义上下文中对象在实际屏幕中所需的大小。
2.3. 组件大小
因为布局管理器负责管理容器里的组件的位置和大小,因此,通常不需要自己去设定组件的大小或位置。如果想这样做(使用setLocation(),setSize()或setBounds()方法中的任何一种),布局管理器将覆盖你的决定。
如果使用标准布局管理器不能满足你的需要,必须自己控制组件的大小或位置时,你可以通过下述方法来中止布局管理器:
MyContainer.setLayout(null);
做完这一步,必须对所有的组件使用setLocation(),setSize()或setBounds(),来将它们定位在容器中。请注意,由于窗口系统和字体大小之间的不同,这种办法将导致从属于平台的布局。更好的途径是创建布局管理器的新子类。
3. 框架(Frames)
Frame是Window的一个子类。它是带有标题和缩放角的窗口。它继承于Java.awt.Container,因此,可以用add()方式来给框架添加组件。框架的缺省布局管理器就是BorderLayout。可以用setLayout()方式来改变布局管理器。
Frame类中的构造函数 Frame(String)用由String规定的标题来创建一个新的不可见的框架对象。当它还处于不可见状态时,将所有组件添加到框架中。例如:
import java.awt.*;
public class MyFrame extends Frame {
public static void main (String args[]) {
MyFrame fr = new MyFrame("Hello Out There!");
fr.setSize(500,500);
fr.setBackground(Color.blue);
fr.setVisible(true);
}
public MyFrame (String str) {
super(str);
}
}
上述程序创建了下述框架,它有一个具体的标题、大小及背景颜色。
注:在框架显示在屏幕上之前,必须做成可见的(通过调用程序setVisible(true)),而且其大小是确定的(通过调用程序setSize()或pack())。
4. Panels
象Frames一样,Panels提供空间来捆绑GUI组件,包括其它面板。每个面板都可以有它自己的布管理程序。一旦一个面板对象被创建,为了能看得见,它必须添加到窗口或框架对象上。用Container类中的add()方式可以做到这一点。
下面的程序创建了一个小的黄色面板,并将它加到一个框架对象上:
import java.awt.*;
public class FrameWithPanel extends Frame {
// Constructor
public FrameWithPanel (String str) {
super (str);
}
public static void main (String args[]) {
FrameWithPanel fr = new FrameWithPanel ("Frame with Panel");
Panel pan = new Panel();
fr.setSize(200,200);
fr.setBackground(Color.blue);
fr.setLayout(null); //override default layout mgr
pan.setSize (100,100);
pan.setBackground(Color.yellow);
fr.add(pan);
fr.setVisible(true);
}
}
5. 容器布局(Container Layout)
容器中组件的布局通常由布局管理器控制。每个Container(比如一个Panel或一个Frame)都有一个与它相关的缺省布局管理器,它可以通过调用setLayout()来改变。
布局管理器负责决定布局策略以及其容器的每一个子组件的大小。
5.1. 布局管理器
Java编程语言包含下面的布局管理器:
-Flow Layout—Panel和Applets的缺省布局管理器
-Border Layout—Window、Dialog及Frame的缺省管理程序
-Grid Layout
-Card Layout
-GridBag Layout
GridBag布局管理器在本模块中不深入讨论。
下图阐述了容器的默认布局管理器
5.2. FlowLayout的一个简单例子
这个样板代码阐述了几个要点,将在下一节讨论。
1.import java.awt.*;
2.
3. public class ExGui {
4. private Frame f;
5. private Button b1;
6. private Button b2;
7.
8. public static void main(String args[]) {
9. ExGui guiWindow = new ExGui();
10. guiWindow.go();
11. }
12.
13. public void go() {
14. f = new Frame("GUI example");
15. f.setLayout(new FlowLayout());
16. b1 = new Button("Press Me");
17. b2 = new Button("Don't Press Me");
18. f.add(b1);
19. f.add(b2);
20. f.pack();
21. f.setVisible(true);
22. }
23.}
这段代码会生成如下界面:
图10-5
5.2.1. main()方法
本例中第8行main()方法有两个作用。首先,它创建了ExGui对象的一个实例。回想一下,直到一个实例存在,还没有被称做f,b1和b2的真实数据项可以使用。第二,当数据空间被创建时,main()在该实例的上下文中调用实例方法go()。在go()中,真正的运行才开始。
5.2.2. new Frame (“GUI Example”)
这个方法创建Java.awt.Frame类的一个实例。根据本地协议,在Java编程语言中,Frame是顶级窗口,带有标题条,在这种情况下,标题条由构造函数的参数“GUI Example”定义,此时Frame是不可见的,大小为零。
5.2.3. f.setLayout (new FlowLayout())
这个方法创建Flow布局管理器的一个实例,并将它安装在框架中。Frame默认的布局管理器是BorderLayout,但本例中没有使用。Flow布局管理器在AWT中是最简单的,它在某种程度上象一个页面中的单词被安排成一行一行的那样来定位组件。请注意,Flow布局缺省地将每一行居中。
5.2.4. new Button(“Press Me”)
这个方法创建Java.awt.Button类的一个实例。按钮是从本地窗口工具包中取出的一个标准按钮。按钮标签由构造函数的参数字符串定义。
5.2.5. f.add(b1)
这个方法告诉框架f,它将包容组件b1。b1的大小和位置受从这一点向前的Frame布局管理器的控制。
5.2.6. f.pack()
这个方法告诉框架来设定大小,能恰好密封它所包含的组件。
5.2.7. f.setVisible(true)
这个方法使框架以及其所有的内容变成用户看得见的东西。
6. 布局管理器
6.1. FlowLayout
前面所用的FlowLayout布局管理器对组件逐行地定位。每完成一行,一个新行便又开始。与其它布局管理器不一样,FlowLayout布局管理器不它所管理的组件的大小,而是允许它们有自己的最佳大小。Flow布局构造程序参数允许将组件左对齐或右对齐(缺省为居中)。如果想在组件之间创建一个更大的最小间隔,可以规定一个界限。
当用户对由Flow布局管理的区域进行缩放时,布局就发生变化。如:
下面的例子就是如何用类容器的setLayout()方法来创建Flow布局对象并安装它们。
setLayout(new FlowLayout(int align, int hgap, int vgap));
align的值必须是FlowLayout.LEFT, FlowLayout.RIGHT,或 FlowLayout.CENTER。例如:
setLayout(new FlowLayout(FlowLayout.RIGHT, 20, 40));
下述程序构造并安装一个新Flow布局,它带有规定好的对齐方式以及一个缺省的5单位的水平和垂直间隙。
setLayout(new FlowLayout(FlowLayout.LEFT));
下述程序构造并安装一个新Flow布局,它带有规定好的居中对齐方式和一个缺省的5单位的水平和垂直间隙。
setLayout(new FlowLayout());
下面的代码将几个按钮添加到框架中的一个Flow布局中:
import java.awt.*;
public class MyFlow {
private Frame f;
private Button button1, button2, button3;
public static void main (String args[]) {
MyFlow mflow = new MyFlow ();
mflow.go();
}
public void go() {
f = new Frame ("Flow Layout");
f.setLayout(new FlowLayout());
button1 = new Button("Ok");
button2 = new Button("Open");
button3 = new Button("Close");
f.add(button1);
f.add(button2);
f.add(button3);
f.setSize (100,100);
f.setVisible(true);
}
}
6.2. BorderLayout
BorderLayout布局管理器为在一个Panel或Window中放置组件提供一个更复杂的方案。BorderLayout布局管理器包括五个明显的区域:东、南、西、北、中。
北占据面板的上方,东占据面板的右侧,等等。中间区域是在东、南、西、北都填满后剩下的区域。当窗口垂直延伸时,东、西、中区域也延伸;而当窗口水平延伸时,东、西、中区域也延伸。
BorderLayout布局管理器是用于Dialog和Frame的缺省布局管理器。
下面这一行构造并安装一个新Border布局管理器,在组件之间没有间隙:
setLayout(new BorderLayout());
这一行构造并安装一个Border布局,在组件之间有由hgap和 vgap 规定的间隙:
setLayout(new BorderLayout(int hgap, int vgap);
在布局管理器中组件必须被添加到指定的区域,而且还看不见。区域名称拼写要正确。可以使用Border布局管理器来产生布局,且带有在缩放时在一个方向、另一方向或双方向上都延伸的元素。
如果离开一个Border布局未使用的区域,好象它的大小为0。区域即使在不含组件的情况下仍然呈现为背景。可以仅将单个组件添加到Border布局管理器五个区域的每一个当中。如果添加不止一个,只有最后一个看得见。后面的模块将演示如何用中间容器来允许不止一个组件被放在单个Border布局管理器区域的空间里。
下面的代码对前例进行了修改,表示出了Border布局管理器的特性。可以用从Container类继承的setLayout()方法来将布局设定为Border布局。
1.import java.awt.*;
2.
3.public class ExGui2 {
4. private Frame f;
5. private Button bn, bs, bw, be, bc;
6.
7. public static void main(String args[]) {
8. ExGui2 guiWindow2 = new ExGui2();
9. guiWindow2.go();
10. }
11.
12. public void go() {
13. f = new Frame("Border Layout");
14. bn = new Button("B1");
15. bs = new Button("B2");
16. be = new Button("B3");
17. bw = new Button("B4");
18. bc = new Button("B5");
19.
20. f.add(bn, BorderLayout.NORTH);
21. f.add(bs, BorderLayout.SOUTH);
22. f.add(be, BorderLayout.EAST);
23. f.add(bw, BorderLayout.WEST);
24. f.add(bc, BorderLayout.CENTER);
25.
26. f.setSize (200, 200);
27. f.setVisible(true);
28. }
29.}
这段代码产生如下界面:
6.3. GridLayout
GridLayout布局管理器为放置组件提供了灵活性。用许多行和列来创建管理器。然后组件就填充到由管理器规定的单元中。比如,由语句new GridLayout(3,2)创建的有三行两列的GridLayout布局能产生如下六个单元:
图10-8
象BorderLayout布局管理器一样,GridLayout布局管理器中的组件相应的位置不随区域的缩放而改变。只是组件的大小改变。GridLayout布局管理器总是忽略组件的最佳大小。所有单元的宽度是相同的,是根据单元数对可用宽度进行平分而定的。同样地,所有单元的高度是相同的,是根据行数对可用高度进行平分而定的。将组件添加到网格中的命令决定它们占有的单元。单元的行数是从左到右填充,就象文本一样,而列是从上到下由行填充。
程序行:setLayout(new GridLayout());创建并安装一个Grid布局,仅有一行一列。
程序行:setLayout(new GridLayout(int rows, int cols));创建并安装一个带有规定好行数和栏数的Grid布局。
程序行:setLayout(new GridLayout(int rows, int cols, int hgap, int vgap); 创建并安装一个带有规定好行数和栏数的网格布局。hgap和vgap规定组件间各自的间隙。水平间隙放在左右两边及栏与栏之间。垂直间隙放在顶部、底部及每行之间。
图10-8系由如下代码生成:
1.import java.awt.*;
2.public class GridEx {
3. private Frame f;
4. private Button b1, b2, b3, b4, b5, b6;
5.
6. public static void main(String args[]) {
7. GridEx grid = new GridEx();
8. grid.go();
9. }
10.
11. public void go() {
12. f = new Frame("Grid example");
13.
14. f.setLayout (new GridLayout (3, 2));
15. b1 = new Button("1");
16. b2 = new Button("2");
17. b3 = new Button("3");
18. b4 = new Button("4");
19. b5 = new Button("5");
20. b6 = new Button("6");
21.
22. f.add(b1);
23. f.add(b2);
24. f.add(b3);
25. f.add(b4);
26. f.add(b5);
27. f.add(b6);
28.
29. f.pack();
30. f.setVisible(true);
31. }
32.}
6.4. CardLayout
Card布局管理器能将界面看作一系列的卡,在任何时候都仅能看到其中的一个。用add()方法来将卡添加到Card布局中。Card布局管理器的show()方法将请求转换到一个新卡中。下例就是一个带有5张卡的框架。
鼠标点击左面板将视图转换到右面板,等等。
用来创建上图框架的代码段如下所示:
1.import java.awt.*;
2.import java.awt.event.*;
3.
4.public class CardExample implements MouseListener {
5. Panel p1, p2, p3, p4, p5;
6. Label l1, l2, l3, l4, l5;
7.
8. // Declare a CardLayout object to call its methods
9. private CardLayout myCard;
10. private Frame f;
11.
12. public CardExample() {
13. f = new Frame ("Card Test");
14. myCard = new CardLayout();
15.
16. // create the panels that I want // to use as cards
17. p1 = new Panel();
18. p2 = new Panel();
19. p3 = new Panel();
20. p4 = new Panel();
21. p5 = new Panel();
22.
23. // create a label to attach to each panel
24. l1 = new Label("This is the first Panel");
25. l2 = new Label("This is the second Panel");
26. l3 = new Label("This is the third Panel");
27. l4 = new Label("This is the fourth Panel");
28. l5 = new Label("This is the fifth Panel");
29. }
30.
31. public void launchFrame(){
32. f.setLayout(myCard);
33.
34. // change the color of each panel, so they are
35. // easily distinguishable
36. p1.setBackground(Color.yellow);
37. p1.add(l1);
38. p2.setBackground(Color.green);
39. p2.add(l2);
40. p3.setBackground(Color.magenta);
41. p3.add(l3);
42. p4.setBackground(Color.white);
43. p4.add(l4);
44. p5.setBackground(Color.cyan);
45. p5.add(l5);
46.
47. // Set up the event handling here ....
48. p1.addMouseListener(this);
49. p2.addMouseListener(this);
50. p3.addMouseListener(this);
51. p4.addMouseListener(this);
52. p5.addMouseListener(this);
53.
54. // add each panel to my CardLayout
55. f.add(p1, "First");
56. f.add(p2, "Second");
57. f.add(p3, "Third");
58. f.add(p4, "Fourth");
59. f.add(p5, "Fifth");
60.
61. // display the first panel
62. myCard.show(f, "First");
63.
. f.setSize (200, 200);
65. f.setVisible(true);
66. }
67.
68. public void mousePressed(MouseEvent e){
69. myCard.next(f);
70. }
71.
72. public void mouseReleased(MouseEvent e){}
73. public void mouseClicked(MouseEvent e){}
74. public void mouseEntered(MouseEvent e){}
75. public void mouseExited(MouseEvent e){}
76.
77. public static void main (String args[]) {
78. CardExample ct = new CardExample ();
79. ct.launchFrame();
80. }
81.}
6.5. GridBag
除了Flow、Border、Grid和Card布局管理器外,核心Java.awt也提供GridBag布局管理器。
GridBag布局管理器在网格的基础上提供复杂的布局,但它允许单个组件在一个单元中而不是填满整个单元那样地占用它们的最佳大小。网格包布局管理器也允许单个组件扩展成不止一个单元。
7. 创建面板及复杂布局
下面的程序使用一个面板,允许在一个Border布局的北部地区放置两个按钮。这种嵌套法对复杂布局来说是基本的。请注意,就框架本身而论,面板被看作象另一个组件。
1.import java.awt.*;
2.
3.public class ComplexLayoutExample {
4. private Frame f;
5. private Panel p;
6. private Button bw, bc;
7. private Button bfile, bhelp;.
8.
9. public ComplexLayoutExample() {
10. f = new Frame("GUI example 3");
11. bw = new Button("West");
12. bc = new Button("Work space region");
13. bfile = new Button("File");
14. bhelp = new Button("Help");
15. }
16.
17. public void launchFrame(){
18. //Add bw and bc buttons in the frame border
19. f.add(bw, BorderLayout.WEST );
20. f.add(bc, BorderLayout.CENTER );
21. //Create panel for the buttons in the north border
22. p = new Panel();
23. p.add(bfile);
24. p.add(bhelp);
25. f.add(p, BorderLayout.NORTH );
26. //Pack the frame and make it visible
27. f.pack();
28. f.setVisible(true);
29. }
30.
31. public static void main(String args[]) {
32. ComplexLayoutExample gui = new ComplexLayoutExample();
33. gui.launchFrame();
34. }
35.}
当这个例子运行时,其结果如下所示:
如果缩放窗口,它看起来如下:
请注意,现在,Border布局的北部地区有效地保持着两个按钮。事实上,它保持的只是单个面板,但这个面板含有这两个按钮。
面板的大小和位置是由Border布局管理器决定的,一个面板的最佳大小是由该面板中组件的最佳大小来决定的。面板中按钮的大小和位置受Flow布局的控制,该布局是由缺省与面板相关联的。
8. 练习:建立Java GUIs
8.1. 创建计算器GUI
8.2. 创建帐目GUI
创建一个GUI,它能给模块5中创建的Teller.Java应用程序提供前端用户界面。需要研究一些本模块中没有描述的组件。(它们将在本课程的后面讲解)。
8.3. 检查进步情况
在继续下一个模块前,检查一下,你确实能:
●描述AWT包及其组件
●定义Container组件及布局管理器等术语,以及它们如何一起工作来建立GUI的
●使用布局管理器
●使用Flow、Border、Grid和Card布局管理器来获得所需的动态布局
●添加组件到容器
●正确使用框架和面板容器
●描述复杂布局与嵌套容器是如何工作的
●在Java程序中,确认下列:
●容器
●相关的布局管理器
●所有组件的布局层次
