javaSE 基础笔记之用户图形界面 GUI
第十章 用户图形界面 GUI
学习目标:
² 理解 GUI的基本概念
² 掌握 Frame、Panel 等容器的使用
² 掌握 AWT组件及使用
² 掌握菜单的实现
² 掌握如何控制外观
² 熟悉布局管理器的使用
一:GUI的基本概念
1:什么是GUI
GUI:Graphical User Interface ,图形用户接口,即人机交互图形化用户界面,就是屏幕产品的视觉体验和互动操作部分。经常读作“goo-ee”,或者字母“G-U-I”,或者完整的英文。切记,不要按照汉语拼音读,发出“贵”或者“鬼”的音,闹笑话。
AWT(Abstract Window Toolkit:抽象窗口工具箱),包括了丰富的图形、用户界面组件和布局管理器的支持,还有对界面事件的处理机制等。
2:Component
组件就是:具有图形界面,并能完成一定功能的封装体。
AWT提供用于所有Java 应用程序中的基本 GUI 组件,还为应用程序提供与机器的界面。这将保证一台计算机上出现的东西与另一台上的相一致。
在学AWT 之前,简单回顾一下对象层次。记住,超类是可以扩展的,它们的属性是可继承的。而且,类可以被抽象化,这就是说,它们是可被分成子类的模板,子类用于类的具体实现。
显示在屏幕上的每个GUI组件都是抽象类组件的子类。也就是说,每个从组件类扩展来的图形对象都与允许它们运行的大量方法和实例变量共享。
3:Container
容器就是:用于包含其它组件的组件。
Container是Component的一个抽象子类,它允许其它的组件被嵌套在里面。这些组件也可以是允许其它组件被嵌套在里面的容器,于是就创建了一个完整的层次结构。在屏幕上布置GUI组件,容器是很有用的。Panel是 Container 的最简单的类。Container的另一个子类是Window。
Window是Java.awt.Window.的对象。Window 是显示屏上独立的本机窗口,它独立于其它容器。
Window 有两种形式:Frame(框架)和 Dialog(对话框)。Frame 和 Dialog 是 Window 的子类。Frame 是一个带有标题和缩放角的窗口。对话没有菜单条。尽管它能移动,但它不能缩放。
Panel 是Java.awt.Panel的对象。Panel包含在另一个容器中,或是在 Web浏览器的窗口中。Panel 确定一个四边形,其它组件可以放入其中。Panel 必须放在 Window 之中(或Window的子类中)以便能显示出来。
注—容器不但能容纳组件,还能容纳其它容器,这一事实对于建立复杂的布局是关键的,也是基本的。
4:组件定位
容器里的组件的位置是由布局管理器决定的。 容器对布局管理器的特定实例保持一个引用。当容器需要定位一个组件时,它将调用布局管理器来做。当决定一个组件的大小时,同样如此。布局管理器完全控制容器内的所有组件。它负责计算并定义上下文中对象在实际屏幕中所需的大小。
5:组件大小
因为布局管理器负责容器里的组件的位置和大小, 因此不需要总是自己去设定组件的大小或位置。如果想这样做(使用 setLocation(),setSize()或 setBounds()方法中的任何一种),布局管理器将覆盖你的决定。
如果必须控制组件的大小或位置,而使用标准布局管理器做不到,那就可能通过将下述方法调用发送到容器中来中止布局管理器:setLayout(null); 做完这一步,必须对所有的组件使用 setLocation(),setSize()或 setBounds(),来将它们定位在容器中。请注意,由于窗口系统和字体大小之间的不同,这种办法将导致从属于平台的布局。更好的途径是创建布局管理器的新子类。
6:其它概念
在这里,再介绍几个其它的概念:
(1):界面是“画”出来的
(2):界面是“叠加”出来的,如果从侧面看,可以分做很多层
(3) :常见的界面组合方式是:组件放在 Panel 里面,Panel 放在 Frame 上。也就是说,通常用 Panel 来进行界面的组合,一个 Panel 就是一个界面,那么界面的切换就相当于切换Frame里面的Panel。
二:容器的基本使用
1:Frame的使用
Frames 是 Window 的一个子类。它是带有标题和缩放角的窗口。它继承于Java.awt.Container,因此,可以用add()方式来给框架添加组件。框架的缺省布局管理器就是Border Layout。它可以用setLayout()方式来改变。框架类中的构造程序 Frame(String)用由 String 规定的标题来创建一个新的不可见的框架对象。当它还处于不可见状态时,将所有组件添加到框架中。
1 1. import java.awt.*; 2 3 2. public class MyFrame extends Frame { 4 5 3. public static void main (String args[]) { 6 7 6. MyFrame fr = new MyFrame("Hello Out There!"); 8 9 7. fr.setSize(500,500); 10 11 4. fr.setBackground(Color.blue); 12 13 5. fr.setVisible(true); 14 15 6. } 16 17 7. public MyFrame (String str) { 18 19 8. super(str); 20 21 9. } 22 23 10. }
上述程序创建了下述框架,它有一个具体的标题、大小及背景颜色。
注—在框架显示在屏幕上之前,必须做成可见的(通过调用程序 setVisible(true)),而且其大小是确定的(通过调用程序 setSize()或 pack())。
2:Panel的使用
象Frames一样,Panels 提供空间来连接任何 GUI组件,包括其它面板。每个面板都可以有它自己的布管理程序。
一旦一个面板对象被创建,为了能看得见,它必须添加到窗口或框架对象上。用Container 类中的add()方式可以做到这一点。下面的程序创建了一个小的黄色面板,并将它加到一个框架对象上:
1 1. import java.awt.*; 2 3 2. public class FrameWithPanel extends Frame { 4 5 3. 6 7 4. // Constructor 8 9 5. public FrameWithPanel (String str) { 10 11 6. super (str); 12 13 7. } 14 15 8. 16 17 9. public static void main (String args[]) { 18 19 10. FrameWithPanel fr = 20 21 11. new FrameWithPanel ("Frame with Panel"); 22 23 12. Panel pan = new Panel(); 24 25 13. 26 27 14. fr.setSize(200,200); 28 29 15. fr.setBackground(Color.blue); 30 31 16. fr.setLayout(null); //override default layout mgr 32 33 17. pan.setSize (100,100); 34 35 18. pan.setBackground(Color.yellow); 36 37 19. 38 39 20. fr.add(pan); 40 41 21. fr.setVisible(true); 42 43 22. } 44 45 23. ....
三:AWT组件的使用
AWT组件提供了控制界面外观的机制,包括用于文本显示的颜色和字体。此外,AWT还支持打印。这个功能是在JDK1.1之后中引入的。
1:按钮(Button)
你已经比较熟悉 Button 组件了。这个组件提供了“按下并动作”的基本用户界面。可
以构造一个带文本标签的按钮,用来告诉用户它的作用。
Button b = new Button("Sample");
b.addActionListener(this);
add(b);
任何实现了被注册为监听者的 ActionListener 接口的类,它的 actionPerformed()方
法将在一个按钮被鼠标点击“按下”时被调用。
1 public void actionPerformed(ActionEvent ae) { 2 3 System.out.println("Button press received."); 4 5 System.out.println("Button's action command is: " + 6 7 ae.getActionCommand()); 8 9 }
按钮被按下时调用的 getActionCommand()方法在缺省情况下将返回标签字符串。用按
钮的setActionCommand()方法改变动作命令和标签。
1 Button b = new Button("Sample"); 2 3 b.setActionCommand("Action Command Was Here!"); 4 5 b.addActionListener(this); 6 7 add(b);
2: 复选框(Checkbox)
Checkbox 组件提供一种简单的“开/关”输入设备,它旁边有一个文本标签。
1 Frame f = new Frame("Checkbox") 2 3 Checkbox one = new Checkbox("One", true); 4 5 Checkbox two = new Checkbox("Two", false); 6 7 Checkbox three = new Checkbox("Three", true); 8 9 one.addItemListener(this); 10 11 two.addItemListener(this); 12 13 three.addItemListener(this); 14 15 f.add(one); 16 17 f.add(two); 18 19 f.add(three);
选取或不选取(取消)一个复选框的事件将被送往 ItemListener 接口。所传递的ItemEvent 包含 getStatechange()方法,它根据实际情况返回 ItemEvent.DESELECTED 或ItemEvent.SELECTED。getItem()方法将受到影响的复选框作为一个表示这个复选框标签的String对象返回。
1 class Handler implements ItemListener { 2 3 public void itemStateChanged(ItemEvent ev) { 4 5 String state = "deselected"; 6 7 if (ev.getStateChange() == ItemEvent.SELECTED){ 8 9 state = "selected"; 10 11 12 13 } 14 15 System.out.println(ev.getItem() + " " + state); 16 17 } 18 19 } 20 21
3 复选框组-单选框(Checkbox group-Radio Button)
复选框组提供了将多个复选框作为互斥的一个集合的方法,因此在任何时刻,这个集合中只有一个复选框的值是true。值为 true 的复选框就是当前被选中的复选框。你可以使用带有一个额外的 CheckboxGroup 参数的构造函数来创建一组中的每个复选框。正是这个CheckBoxGroup 对象将各个复选框连接成一组。如果你这么做的话,那么复选框的外观会发生改变,而且所有和一个复选框组相关联的复选框将表现出“单选框”的行为。
1 Frame f = new Frame("Checkbox Group"); 2 3 CheckboxGroup cbg = new CheckboxGroup(); 4 5 Checkbox one = new Checkbox("One", false, cbg); 6 7 Checkbox two = new Checkbox("Two", false, cbg); 8 9 Checkbox three = new Checkbox("Three", true, cbg); 10 11 one.addItemListener(this); 12 13 two.addItemListener(this); 14 15 three.addItemListener(this); 16 17 f.add(one); 18 19 f.add(two); 20 21 f.add(three);
4 下拉列表(Choice)
下拉列表组件提供了一个简单的“从列表中选取一个”类型的输入。例如:
1 Frame f = new Frame("Choice"); 2 3 Choice c = new Choice(); 4 5 c.add("First"); 6 7 8 9 c.add("Second"); 10 11 c.add("Third"); 12 13 c.addItemListener(this); 14 15 f.add(c);
点击下拉列表组件时,它会显示一个列表,列表中包含了所有加入其中的条目。注意所加入的条目是String对象。
ItemListener 接口用来观察下拉列表组件的变化,其细节和复选框的相同。
5 画布(Canvas)
画布提供了一个空白(背景色)的空间。除非你用setSize()显式地定义它的大小,否则
它的大小就是0×0。
画布的空间可以用来绘图、显示文本、接收键盘或鼠标的输入。后面的模块将告诉你如
何有效地在AWT 中绘图。
通常,画布用来提供一个一般的绘图空间或者为客户组件提供工作区域。
画布可以“监听”所有适用于一个普通组件的事件。特别地,你还可能想增加KeyListener、MouseMotionListener 和 MouseListener 对象,以允许某种方式对用户输入作出反应。
下面是画布的一个范例。每击一次键,这个程序就改变一次画布的颜色。
1 import java.awt.*; 2 3 import java.awt.event.*; 4 5 import java.util.*; 6 7 public class MyCanvas extends Canvas 8 9 implements KeyListener { 10 11 int index; 12 13 Color colors[] = {Color.red, Color.green, Color.blue }; 14 15 public void paint(Graphics g) { 16 17 g.setColor(colors[index]); 18 19 g.fillRect(0,0,getSize().width,getSize().height); 20 21 } 22 23 24 25 public static void main(String args[]) { 26 27 Frame f = new Frame("Canvas"); 28 29 MyCanvas mc = new MyCanvas(); 30 31 f.add(mc,BorderLayout.CENTER); 32 33 f.setSize(150, 150); 34 35 mc.requestFocus(); 36 37 mc.addKeyListener(mc); 38 39 f.setVisible(true); 40 41 } 42 43 44 45 public void keyTyped(KeyEvent ev) { 46 47 index++; 48 49 if (index == colors.length) { 50 51 index =0; 52 53 } 54 55 repaint(); 56 57 } 58 59 60 61 public void keyPressed(KeyEvent ev) { 62 63 } 64 65 66 67 public void keyReleased(KeyEvent ev) { 68 69 } 70 71 } 72 73 74 75
6 标签(Label)
一个标签对象显示一行静态文本。程序可以改变文本,但用户不能改变。标签没有任何特殊的边框和装饰。
1 Label l = new Label( " Hello " ); 2 3 add(l);
标签通常不处理事件,但也可以按照和画布相同的方式来处理事件。也就是说,只有调
用了requestFocus()方法后,才能可靠地检取击键事件。
7 文本域(Textfield)
文本域是一个单行的文本输入设备。例如:
1 TextField f = new TextField("Single line" " , 30); 2 3 f.addActionListener(this); 4 5 add(f);
因为只允许有一行,所以当按下 Enter 或 Return 键时,ActionListener 可以通过
actionPerformed()知道这个事件。如果需要,还可以增加其他的组件监听者。
除了注册一个 ActionListener,你还可以注册一个TextListener来接收关于个别击键
的通知。它的回调方法是textValueChanged(TextEvent)。
8 文本区(TextArea)
文本区是一个多行多列的文本输入设备。你可以用 setEditable(boolean)将它设置成
只读的。文本区将显示水平和垂直的滚动条。
下面这个范例创建了一个4行×30字符的文本,最初它含有“Hello!”。
1 TextArea t = new TextArea( " Hello! " , 4, 30); 2 3 t.addTextListener(this); 4 5 add(t);
你用 addTexListener指定的监听者将以和文本域相同的方式接收到关于击键的通知。
你可以给文本区增加一般的组件监听者,然而,由于文本是多行的,按下 Enter键将导
致把另一个字符送入缓冲。如果你需要识别“输入的结束”,你可以在文本区旁放置一个“应
用”或“确认”按钮,以便用户指明“输入的结束”。
9 文本组件(Text Components)
文本区和文本域的文档都分为两个部分。如果你查找一个称为文本组件的类,你会找到若干个文本区和文本域共有的方法。例如,文本区和文本域都是文本组件的子类。
你已经知道文本区和文本域类的构造函数允许你指定显示所用的列数。 记住所显示的组件大小是由布局管理器决定的,因此这些设置可能被忽略。进而,列数是按所用字体的平均宽度计算的。如果使用一种空间比例字体,实际显示的字符数可能相差很大。由于文本组件实现了 TextListener,诸如文本域、文本区及其它子类都有对击键事件的内置支持。
10 列表(list)
一个列表将各个文本选项显示在一个区域中,这样就可以在同时看到若干个条目。列表
可以滚动,并支持单选和多选两种模式。例如:
List l = new List(4, true); 1.add("Hello"); 1.add("there"); 1.add("how"); 1.add("are");
构造函数的数值参数定义了按可见列计算的列表高度。这个值也可能被布局管理器覆盖。一个值为true的布尔型参数表明这个列表允许用户作多个选择。
选取或取消一个条目时,AWT将一个 ItemEvent的实例送往列表。用户双击滚动列表中的一个条目时,单选模式和多选模式的列表都会产生一个 ActionEvent。根据每个平台的约定来决定列表中的条目是否被选取。对于UNIX/Motif环境,单击会加亮列表中的一个条目,只有双击才会触发列表事件(选取条目)。
11:对话框(Dialog)
对话框组件与一个框架相关联。 它是一个带有一些装饰的自由窗口。它与框架的区别在于所提供的一些装饰,而且你可以生成一个“模式”对话框,它在被关闭前将存储所有窗口的输入。
对话框可以是无模式和模式的。 对于无模式对话框,用户可以同时与框架和对话框交互。“模式”对话框在被关闭前将阻塞包括框架在内的其他所有应用程序的输入。
由于对话框是窗口的子类,所以它的缺省布局管理器是 Border Layout。
1 Dialog d = new Dialog(f, "Dialog", false); 2 3 d.add(new Label("Hello, I'm a Dialog",Border.Layout.CENTER)); 4 5 d.pack();
对话框在创建时通常是不可见的。通常在对按下按钮等用户输入作出反应时,才显示对话框。
1 public void actionPerformed(ActionEvent ev) { 2 3 d.setVisible(true); 4 5 }
要隐藏对话框,你必须调用 setVisible(false)。典型的做法是对它添加一个WindowListener,并等待对那个监听者的 windowClosing()调用。这和处理一个框架的关闭是平行的。
12:文件对话框(File Dialog)
文件对话框是文件选择设备的一个实现。它有自己的自由窗口,以及窗口元素,并且允
许用户浏览文件系统,以及为以后的操作选择一个特定的文件。例如:
1 FileDialog d = new FileDialog(parentFrame, "FileDialog"); 2 3 d.setVisible(true);// block here until OK selected 4 5 String fname = d.getFile();
通常并不需要处理 FileDialog 的事件。调用 setVisible(true)将阻塞事件,直至用户选择
OK,这时会请求用户选择的文件名。这个信息将作为一个 String返回。
13:滚动面板(Scroll Pane)
滚动面板提供了一种不能作为自由窗口的通用容器。它应当总是和一个容器相关联(例如,框架)。它提供了到一个更大的区域的视窗以及操纵这个视窗的滚动条。例如:
1 Frame f = new Frame("ScrollPane"); 2 3 Panel p = new Panel(); 4 5 ScrollPane sp = new ScrollPane(); 6 7 p.setLayout(new GridLayout(3, 4)); 8 9 sp.add(p); 10 11 f.add(sp, "Center"); 12 13 f.setSize(200, 200); 14 15 f.serVisible(true);
滚动面板创建和管理滚动条,并持有一个组件。你不能控制它所用的布局管理器。你可以将一个面板加入到滚动面板中,配置面板的布局管理器,并在那个面板中放置你的组件。
通常,你不处理滚动面板上的事件;这些事件通过滚动面板所包含的组件进行处理。
四:菜单的实现
菜单与其他组件有一个重要的不同:你不能将菜单添加到一般的容器中,而且不能使用布局管理器对它们进行布局。你只能将菜单加到一个菜单容器中。然而,你可以将一个Jmenuswing组件加到一个Jcontainer中。 你可以通过使用setMenuBar()方法将菜单放到一个框架中,从而启动一个菜单“树”。从那个时刻之后,你可以将菜单加到菜单条中,并将菜单或菜单项加到菜单中。
弹出式菜单是一个例外,因为它们可以以浮动窗口形式出现,因此不需要布局。
1: 帮助菜单
菜单条的一个特性是你可以将一个菜单指定为帮助菜单。这可以用 setHelpMenu(Menu)来做到。要作为帮助菜单的菜单必须加入到菜单条中;然后它就会以和本地平台的帮助菜单同样的方式被处理。对于X/Motif 类型的系统,这涉及将菜单条放置在菜单条的最右边。
2: 菜单条(MenuBar)
一个菜单条组件是一个水平菜单。它只能加入到一个框架中,并成为所有菜单树的根。在一个时刻,一个框架可以显示一个菜单条。然而,你可以根据程序的状态修改菜单条,这样在不同的时刻就可以显示不同的菜单。例如:
1 Frame f = new Frame("MenuBar"); 2 3 MenuBar mb = new MenuBar(); 4 5 f.setMenuBar(mb);
![]()
菜单条不支持监听者。作为普通菜单行为的一部分,在菜单条的区域中发生的预期事件会被自动处理。
3: 菜单组件
菜单组件提供了一个基本的下拉式菜单。它可以加入到一个菜单条或者另一个菜单中。
例如:
1 MenuBar mb = new MenuBar(); 2 3 Menu m1 = new Menu("File"); 4 5 Menu m2 = new Menu("Edit"); 6 7 Menu m3 = new Menu("Help"); 8 9 10 11 mb.add(m1); 12 13 mb.add(m2); 14 15 mb.setHelpMenu(m3); 16 17 f.setMenuBar(mb);
注-这里显示的菜单是空的,这正是 File菜单的外观。
你可以将一个 ActionListener 加入到菜单对象,但这种做法是罕见的。正常情况下,菜单用来显示和控制菜单条,这将在后面讨论。
4:菜单项(MenuItem)
菜单项组件是菜单树的文本“叶”结点。它们通常被加入到菜单中,以构成一个完整的菜单。
例如:
1 Menu m1 = new Menu("File"); 2 3 MenuItem mi1 = new MenuItem("New"); 4 5 MenuItem mi2 = new MenuItem("Load"); 6 7 MenuItem mi3 = newMenuItem ("Save"); 8 9 MenuItem mi4 = new MenuItem("Quit"); 10 11 mi1.addActionListener(this); 12 13 mi2.addActionListener(this); 14 15 mi3.addActionListener(this); 16 17 m1.add(mi1); 18 19 m1.add(mi2); 20 21 m1.addSeparator(); 22 23 m1.add(mi3);
通常,将一个 ActionListener加入到一个菜单项对象中,以提供菜单的行为。
5: 复选菜单项(CheckboxMenuItem)
复选菜单项是一个可复选的菜单项,可以在菜单上有选项(“开”或“关”)。例如:
1 Menu m1 = new Menu("File"); 2 3 MenuItem mi1 = new MenuItem("Save"); 4 5 CheckboxMenuItem mi2 = 6 7 new CheckboxMenuItem("Persistent"); 8 9 mi1.addItemListener(this); 10 11 mi2.addItemListener(this); 12 13 m1.add(mi1); 14 m1.add(mi2);
![]()
应当用 ItemListener 接口来监视复选菜单。因此当复选框状态发生改变时,就会调用itemStateChanged()方法。
6: 弹出式菜单(PopupMenu)
弹出式菜单提供了一种独立的菜单,它可以在任何组件上显示。你可以将菜单条目和菜
单加入到弹出式菜单中去。
例如:
1 Frame f = new Frame("PopupMenu"); 2 3 Button b = new Button("Press Me"); 4 5 PopupMenu p = new PopupMenu("Popup"); 6 7 MenuItem s = new MenuItem("Save"); 8 9 MenuItem l = new MenuItem("Load"); 10 11 b.addActionListener(this); 12 13 f.add(b,Border.Layout.CENTER); 14 15 p.add(s); 16 17 p.add(l); 18 19 f.add(p);
为了显示弹出式菜单,你必须调用显示方法。显示需要一个组件的引用,作为 x 和 y 坐标轴的起点。通常,你要为此使用组件的触发器。在上面这个范例中,触发器是 Button b。
弹出式菜单(续)
1 public void actionPerformed(ActionEvent ev) { 2 3 p.show(b, 10, 10); // display popup 4 5 // at (10,10) relative to b 6 7 }
注-弹出式菜单必须加入到一个“父”组件中。这与将组件加入到容器中是不同的。在上面这个范例中,弹出式菜单被加入到周围的框架中。
五:控制外观
你可以控制在AWT组件中所显示的文本的前景背景颜色、背景颜色和字体。
1: 颜色
有两个方法用来设置组件的颜色:
- setForeground()
- getForeground()
这两个方法都带有一个参数,参数是java.awt.Color类的实例。你可以使用常数颜色,如Color.red,Color.blue等。所有预定义的颜色列在 Color 类的文档中。
此外,你可以创建一个特定的颜色,例如:
int r = 255, g = 255, b = 0;
Color c = new Color(r, g, b);
上述构造函数根据指定的红色、绿色和蓝色的亮度(它们的范围都是 0~255)来创建一个颜色。
2: 字体
在组件中显示时所用的字体可以用 setFont()方法来设置。这个方法的参数应当是java.awt.Font 类的实例。
没有为字体定义常数,但你可以根据字体的名称,风格,磅值来创建一个字体。
Font f = new Font("TimesRoman", Font.PLAIN, 14);
有效的字体名称包括:
- Dialog
- Helvetica
- TimesRoman
- Courier
可以通过调用Toolkit 对象的getFontlist()方法来得到完整的列表。GetToolkit()方法是用来在显示 toolkit 后获得 toolkit 的。还有另外一种方法,你可以使用缺省的toolkit,它可以通过调用Toolkit.getDefaultToolkit()来获得。
字体风格常数实际上是int 值,即:
- Font.BOLD
- Font.ITALIC
- Font.PLAIN
- Font.BOLD+ Font.ITALIC
磅值必须使用 int值来指定。
六:布局管理器和布局
容器中组件的布局通常由布局管理器控制。每个 Container(比如一个 Panel 或一个Frame)都有一个与它相关的缺省布局管理器,它可以通过调用 setLayout()来改变。
布局管理器负责决定布局方针以及其容器的每一个子组件的大小。
下面的布局管理器包含在Java编程语言中:
Flow Layout—Panel和Applets的缺省布局管理器
Border Layout—Window、Dialog 及 Frame的缺省管理程序
Grid Layout
Card Layout
GridBag Layout
GridBag布局管理器在本模块中不深入讨论。
1: Flow布局管理器
Flow 布局管理器不限制它所管理的组件的大小,而是允许它们有自己的最佳大小。
如果想将组件设定缺省居中的话,Flow布局构造程序参数允许将组件左对齐或右对齐。
如果想在组件之间创建一个更大的最小间隔,可以规定一个界限。当用户对由Flow 布局管理的区域进行缩放时,布局就发生变化。如:
下面的例子就是如何用类容器的 setLayout()方法来创建 Flow布局对象并安装它们。
setLayout(new FlowLayout(int align,int hgap, int vgap));
对齐的值必须是FlowLayout.LEFT, FlowLayout.RIGHT,或 FlowLayout.CENTER。例如:
setLayout(new FlowLayout(FlowLayout.RIGHT, 20, 40));
Flow Layout的一个简单例子
1 import java.awt.*; 2 3 public class ExGui { 4 5 private Frame f; 6 7 private Button b1; 8 9 private Button b2; 10 11 public static void main(String args[]) { 12 13 ExGui guiWindow = new ExGui(); 14 15 guiWindow.go(); 16 17 } 18 19 public void go() { 20 21 f = new Frame("GUI example"); 22 23 f.setLayout(new FlowLayout()); 24 25 b1 = new Button("Press Me"); 26 27 b2 = new Button("Don't Press Me"); 28 29 f.add(b1); 30 31 f.add(b2); 32 33 f.pack(); 34 35 f.setVisible(true); 36 37 } 38 39 }
main()方法
本例中第 8 行 main()方法有两个作用。首先,它创建了 ExGui 对象的一个实例。回想一下,直到一个实例存在,还没有被称做 f,b1 和 b2 的真实数据项可以使用。第二,当数据空间被创建时,main()在该实例的上下文中调用实例方法 go()。在 go()中,真正的运行才开始。
new Frame (“GUI Example”)
这个方法创建Java.awt.Frame类的一个实例。 根据本地协议,在Java编程语言中, Frame是顶级窗口,带有标题条—在这种情况下,标题条由构造程序参数“GUI Example”定义—缩放柄,以及其它修饰。
f.setLayout (new FlowLayout())
这个方法创建 Flow 布局管理器的一个实例,并将它安装在框架中。对于每个 Frame、Border布局来说,都有一个布局管理器,但本例中没有使用。Flow 布局管理器在 AWT 中是最简单的,它在某种程度上象一个页面中的单词被安排成一行一行的那样来定位组件。请注意,Flow布局缺省地将每一行居中。
new Button(“Press Me”)
这个方法创建 Java.awt.Button 类的一个实例。按钮是从本地窗口工具包中取出的一个标准按钮。按钮标签是由构造程序的字符串参数定义的。
f.add(b1)
这个方法告诉框架 f(它是一个容器),它将包容组件 b1。b1的大小和位置受从这一点向前的Frame布局管理器的控制。
f.pack()
这个方法告诉框架来设定大小,能恰好密封它所包含的组件。为了确定框架要用多大,f.pack()询问布局管理器,在框架中哪个负责所有组件的大小和位置。
f.setVisible(true)
这个方法使框架以及其所有的内容变成用户看得见的东西。
2: Border布局管理器
Border 布局管理器为在一个 Panel 或 Window 中放置组件提供一个更复杂的方案。Border布局管理器包括五个明显的区域:东、南、西、北、中。
北占据面板的上方,东占据面板的右侧,等等。中间区域是在东、南、西、北都填满后剩下的区域。当窗口垂直延伸时,东、西、中区域也延伸;而当窗口水平延伸时,东、西、中区域也延伸。
Border布局管理器是用于Dialog和Frame的缺省布局管理器。
注—当窗口缩放时,按钮相应的位置不变化,但其大小改变。
下面的代码对前例进行了修改,表示出了 Border 布局管理器的特性。可以用从Container 类继承的setLayout()方法来将布局设定为 Border 布局。
1 import java.awt.*; 2 3 public class ExGui2 { 4 5 private Frame f; 6 7 private Button bn, bs, bw, be, bc; 8 9 public static void main(String args[]) { 10 11 ExGui2 guiWindow2 = new ExGui2(); 12 13 guiWindow2.go(); 14 15 } 16 17 public void go() { 18 19 f = new Frame("Border Layout"); 20 21 bn = new Button("B1"); 22 23 bs = new Button("B2"); 24 25 be = new Button("B3"); 26 27 bw = new Button("B4"); 28 29 bc = new Button("B5"); 30 31 f.add(bn, BorderLayout.NORTH); 32 33 f.add(bs, BorderLayout.SOUTH); 34 35 f.add(be, BorderLayout.EAST); 36 37 f.add(bw, BorderLayout.WEST); 38 39 f.add(bc, BorderLayout.CENTER); 40 41 f.setSize (200, 200); 42 43 f.setVisible(true); 44 45 } 46 47 }
下面这一行:
setLayout(new BorderLayout());
构造并安装一个新Border布局,在组件之间没有间隙。
这一行
setLayout(new BorderLayout(int hgap, int vgap);
构造并安装一个Border布局,在由 hgap 和 vgap 规定的组件之间有规定的间隙。
在布局管理器中组件必须被添加到指定的区域,而且还看不见。区域名称拼写要正确,尤 其 是在 选择 不 使 用常 量 (如 add(button,”Center”) ) 而 使用
add(button,BorderLayout.CENTER)时。拼写与大写很关键。可以使用 Border 布局管理器来产生布局,且带有在缩放时在一个方向、另一方向或双
方向上都延伸的元素。
注—如果窗口水平缩放,南、北、中区域变化;如果窗口垂直缩放,东、西、中区域变化;
如果离开一个Border 布局未使用的区域,,好象它的大小为 0。中央区域即使在不含组件的情况下仍然呈现为背景。
可以仅将单个组件添加到 Border 布局管理器五个区域的每一个当中。如果添加不止一个,只有最后一个看得见。后面的模块将演示如何用中间容器来允许不止一个组件被放在单个Border布局管理器区域的空间里。
注—布局管理器给予南、北组件最佳高度,并强迫它们与容器一样宽。但对于东、西组件,给予最佳宽度,而高度受到限制。
3: Grid布局管理器
Grid 布局管理器为放置组件提供了灵活性。用许多行和栏来创建管理程序。然后组件就填充到由管理程序规定的单元中。比如,由语句 new GridLayout(3,2)创建的有三行两栏的Grid布局能产生如下六个单元:
因为有 Border 布局管理器,组件相应的位置不随区域的缩放而改变。只是组件的大小改变。
Grid 布局管理器总是忽略组件的最佳大小。所有单元的宽度是相同的,是根据单元数对可用宽度进行平分而定的。同样地,所有单元的高度是相同的,是根据行数对可用高度进行平分而定的。
将组件添加到网格中的命令决定它们占有的单元。单元的行数是从左到右填充,就象文本一样,而页是从上到下由行填充。
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规定组件间各自的间隙。水平间隙放在左右两边及栏与栏之间。垂直间隙放在顶部、底部及每行之间。
注—行和栏中的一个,不是两个同时,可以为0。这就是说,任何数量的对象都可以放在一个行或一个栏中。
示例程序代码如下:
1 import java.awt.*; 2 3 public class GridEx { 4 5 private Frame f; 6 7 private Button b1, b2, b3, b4, b5, b6; 8 9 public static void main(String args[]) { 10 11 GridEx grid = new GridEx(); 12 13 grid.go(); 14 15 } 16 17 public void go() { 18 19 f = new Frame("Grid example"); 20 21 f.setLayout (new GridLayout (3, 2)); 22 23 b1 = new Button("1"); 24 25 b2 = new Button("2"); 26 27 b3 = new Button("3"); 28 29 b4 = new Button("4"); 30 31 b5 = new Button("5"); 32 33 b6 = new Button("6"); 34 35 f.add(b1); 36 37 f.add(b2); 38 39 f.add(b3); 40 41 f.add(b4); 42 43 f.add(b5); 44 45 f.add(b6); 46 47 f.pack(); 48 49 f.setVisible(true); 50 51 } 52 53 }
4: Card布局管理器
Card 布局管理器能将界面看作一系列的卡,其中的一个在任何时候都可见。用 add()方法来将卡添加到Card 布局中。Card布局管理器的show()方法应请求转换到一个新卡中。
下例就是一个带有5张卡的框架。
鼠标点击左面板将视图转换到右面板。
用来创建上图框架的代码段如下所示:
1 import java.awt.*; 2 3 import java.awt.event.*; 4 5 6 7 public class CardTest implements MouseListener { 8 9 Panel p1, p2, p3, p4, p5; 10 11 Label l1, l2, l3, l4, l5; 12 13 // Declare a CardLayout object, 14 15 // to call its methods 16 17 CardLayout myCard; 18 19 Frame f; 20 21 public static void main (String args[]) { 22 23 CardTest ct = new CardTest (); 24 25 ct.init(); 26 27 } 28 29 public void init () { 30 31 f = new Frame ("Card Test"); 32 33 myCard = new CardLayout(); 34 35 f.setLayout(myCard); 36 37 // create the panels that I want 38 39 // to use as cards 40 41 p1 = new Panel(); 42 43 p2 = new Panel(); 44 45 p3 = new Panel(); 46 47 p4 = new Panel(); 48 49 p5 = new Panel(); 50 51 // create a label to attach to each panel, and 52 53 // change the color of each panel, so they are 54 55 // easily distinguishable 56 57 l1 = new Label("This is the first Panel"); 58 59 p1.setBackground(Color.yellow); 60 61 p1.add(l1); 62 63 l2 = new Label("This is the second Panel"); 64 65 p2.setBackground(Color.green); 66 67 p2.add(l2); 68 69 l3 = new Label("This is the third Panel"); 70 71 p3.setBackground(Color.magenta); 72 73 p3.add(l3); 74 75 76 77 l4 = new Label("This is the fourth Panel"); 78 79 p4.setBackground(Color.white); 80 81 p4.add(l4); 82 83 84 85 l5 = new Label("This is the fifth Panel"); 86 87 p5.setBackground(Color.cyan); 88 89 p5.add(l5); 90 91 // Set up the event handling here .... 92 93 √ 94 95 // add each panel to my CardLayout 96 97 f.add(p1, "First"); 98 99 f.add(p2, "Second"); 100 101 f.add(p3, "Third"); 102 103 f.add(p4, "Fourth"); 104 105 f.add(p5, "Fifth"); 106 107 108 109 // display the first panel 110 111 myCard.show(f, "First"); 112 113 114 115 f.setSize (200, 200); 116 117 f.setVisible(true); 118 119 }
5: GridBag 布局管理器
除了 Flow、Border、Grid和Card 布局管理器外,核心 Java.awt也提供 GridBag布局管理器。
GridBag布局管理器在网格的基础上提供复杂的布局,但它允许单个组件在一个单元中而不是填满整个单元那样地占用它们的最佳大小。 网格包布局管理器也允许单个组件扩展成不止一个单元。
七:谈谈 GUI编程中的“画”界面
1:首先是要建立一个 Application的工程
2:一个工程提供一个 Frame
3:每个界面都是一个 Panel,界面复杂程度取决于放在 Panel 里面组件的多少,还有组件的复杂程度
所以,画界面的过程基本上就是“画”Panel,然后再Panel 里面“画”组件的过程。
1:一个Panel的代码的基本构成
经过分析,常见的Panel类里面的代码分成如下3 个部分:
(1):需要出现在界面上的组件的定义
(2):界面初始化的方法
(3):界面事件处理的方法
2:组件的基本使用
分析在“画”界面的过程中,组件的基本使用,步骤如下:
(1) :组件定义和组件初始化
(2):为组件设置相应的属性,通常是组件外观的控制,字体、颜色、大小、位置等
(3):把组件添加到Panel,把 Panel添加到 Frame中,如果是 Frame,那就显示出来
所有的组件基本上都是这么使用,复杂的组件主要是在属性和方法上复杂,但是使用的
方法是差不多的。
练习实践
本章的内容为AWT实践重点:
AWT基础 界面布局程序 1:
获取文件路径
需求:选择一个文件,获取其全路径。
目标:
1、 打开文件对话框、保存文件对话框的使用;
2、 内部类的使用;
3、 如何处理点击事件。
程序:
//: FileDialogNew.java
1 package com.useful.java.part4; 2 3 4 5 import java.awt.*; 6 7 import java.awt.event.*; 8 9 10 11 public class FileDialogNew extends Frame { 12 13 TextField filename = new TextField(); 14 15 TextField directory = new TextField(); 16 17 Button open = new Button("Open"); 18 19 Button save = new Button("Save"); 20 21 public FileDialogNew() { 22 23 setTitle("File Dialog Test"); 24 25 Panel p = new Panel(); 26 27 p.setLayout(new FlowLayout()); 28 29 open.addActionListener(new OpenL()); 30 31 p.add(open); 32 33 save.addActionListener(new SaveL()); 34 35 p.add(save); 36 37 add(p, BorderLayout.SOUTH); 38 39 directory.setEditable(false); 40 41 filename.setEditable(false); 42 43 p = new Panel(); 44 45 p.setLayout(new GridLayout(2,1)); 46 47 p.add(filename); 48 49 p.add(directory); 50 51 add(p, BorderLayout.NORTH); 52 53 } 54 55 class OpenL implements ActionListener { 56 57 public void actionPerformed(ActionEvent e) { 58 59 60 61 // Two arguments, defaults to open file: 62 63 FileDialog d = new FileDialog( 64 65 FileDialogNew.this, 66 67 "What file do you want to open?"); 68 69 d.setFile("*.java"); 70 71 d.setDirectory("."); // Current directory 72 73 d.show(); 74 75 String yourFile = "*.*"; 76 77 if((yourFile = d.getFile()) != null) { 78 79 filename.setText(yourFile); 80 81 directory.setText(d.getDirectory()); 82 83 } else { 84 85 filename.setText("You pressed cancel"); 86 87 directory.setText(""); 88 89 } 90 91 } 92 93 } 94 95 class SaveL implements ActionListener { 96 97 public void actionPerformed(ActionEvent e) { 98 99 FileDialog d = new FileDialog( 100 101 FileDialogNew.this, 102 103 "What file do you want to save?", 104 105 FileDialog.SAVE); 106 107 d.setFile("*.java"); 108 109 d.setDirectory("."); 110 111 d.show(); 112 113 String saveFile; 114 115 if((saveFile = d.getFile()) != null) { 116 117 filename.setText(saveFile); 118 119 directory.setText(d.getDirectory()); 120 121 } else { 122 123 filename.setText("You pressed cancel"); 124 125 directory.setText(""); 126 127 } 128 129 } 130 131 } 132 133 public static void main(String[] args) { 134 135 Frame f = new FileDialogNew(); 136 137 f.addWindowListener( 138 139 new WindowAdapter() { 140 141 public void windowClosing(WindowEvent e) { 142 143 System.exit(0); 144 145 } 146 147 }); 148 149 150 151 f.setSize(250,110); 152 153 f.setVisible(true); 154 155 } 156 157 }
说明:
1、 程序中多次用到内部类,在GUI程序经常用到内部类,内部类编译后其类
名由两部分组成,前者为主类名,后面是本类名,中间用$隔开,如下图所
示:
2、 事件处理时, 使用了接口ActionListener, 这也是通用的事件处理方式之一;
3、 程序运行如下:
作业
1、 构建一个地址本的应用,画出增、删、改、查、列表的界面