首页 > 代码库 > AWT
AWT
概述
所有和AWT编程相关的类都放在java.awt包以及它的子包中,在java.awt包中提供了两个基类表示图形界面元素:Componment和MenuComponment,其中Componment代表一个能以图形化方式显示出来,并且与用户交互的对象。而MenuComponment则代表图形界面的菜单组件。
AWT图形用户界面编程中还有两个重要的概念:Container和LayoutManager,其中Container是一种特殊的Componment,它代表一种容器,可以盛装Componment;而LayoutManager则是容器管理其他组件布局的方式。
容器(Container)是Componment的子类,因此容器对象本身也是一个组件,具有组件的所有性质,可以调用Componment类的所有方法。Componment类提供了如下几个方法:
1、setLocation(int x, int y):设置组件的位置2、setSize(int width, int heigth):设置组件的大小3、setBounds(int x, int y, int width, int heigth):同时设置组件的位置大小4、setVisible(Boolean b):设置该组件可见性
容器还可以盛装其他组件,容器类(Container)提供了几个方法来访问容器中的组件:
1、Componment add(Componment comp):向容器中添加其他组件(该组件可以是普通组件,也可以是容器),并返回添加的组件2、Componment getComponmentAt(int x, int y):返回指定点的组件3、int getComponmentCount():返回该容器内组件的数量4、Componment[] getComponments():返回该容器内所有的组件
AWT主要提供了如下两种主要的容器类型:
Window:可独立存在的顶级窗口;
Panel:可作为容器容纳其他组件,但不能独立存在,必须添加到其他容器中。
其中Window有两个子类Frame(创建窗口)和Dialog(创建对话框)。
Frame代表常见的窗口:1、Frame对象有标题,允许通过拖拉改变窗口的大小、位置;2、初始化时为不可见,可用setVisible(true)显示出来;3、默认使用BordLayout作为布局管理器
import java.awt.*;public class FrameTest{ public static void main(String[] args){ Frame f = new Frame("创建窗口"); f.setBounds(30, 30, 250, 229); f.setVisible(true); } }
注:Java斜杠代表目录 反斜杠转义
上面程序运行,如果点击右上角“X”按钮,并不会关闭,因为还未为该窗口编写任何事件响应。
Panel是AWT中另一个典型的容器,它代表不能独立存在、必须放在其他容器中的容器。Panel外观是一个矩形区域,该区域可盛装其它组件。Panel存在的意义在于为其他组件提供空间,Panel容器具有如下几个特点:1、可作为容器来盛装其他组件,为防止组件提供空间;2、不能单独存在,必须放置到其它容器中;3、默认使用FlowLayout作为布局管理器。
import java.awt.*;public class FrameTest{ public static void main(String[] args){ Frame f = new Frame("创建窗口"); Panel p = new Panel(); p.add(new Button("单击我")); p.add(new TextField(20)); f.add(p); f.setBounds(30, 30, 250, 250); f.setVisible(true); } }
ScrollPane是一个带滚动条的容器,它也不能独立存在,也必须添加到其他容器中,ScrollPane有几个特点:1、可作为容器来盛装其他组件,当组件空间过大时,ScrollPane会自动产生滚动条。也可以通过指定特定的构造器参数来指定默认具有滚动条;2、不能独立存在,必须放到其他容器中;3、默认使用BorderLayout作为布局管理器。ScrollPane通过用于盛装其他容器,通过不允许改变ScrollPane的布局管理器
import java.awt.*;public class FrameTest{ public static void main(String[] args){ Frame f = new Frame("创建窗口"); //指定具有滚动条 ScrollPane p = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); p.add(new Button("单击我")); p.add(new TextField(20)); f.add(p); f.setBounds(30, 30, 250, 250); f.setVisible(true); } }
布局管理器
所有AWT容器都有默认的布局管理器,如果没有指定,使用默认的。
通过setLayout()方法指定布局管理器:
f.setLayout(new XxxLayout());
AWT提供了FlowLayout、BorderLayout、GridLayout、GridBagLayout、CardLayout 5个常用的布局管理器,Swing还提供了一个BoxLayout布局管理器。
FlowLayout布局管理器
FlowLayout布局管理器中,组件像水流一样向某个方向流动(排列),遇到障碍(边界)就折回重头开始排列。在默认情况下,FlowLayout布局管理器从左向右排列所有组件。遇到边界就折回下一行重新开始。
FlowLayout有三个构造器:
1、FlowLayout():使用默认对其方式及默认的垂直间距、水平间距创建FlowLayout布局管理器2、FlowLayout(int align):使用指定的对齐方式及默认的垂直间距、水平间距创建FlowLayout布局管理器3、FlowLayout(int align, int hgap, int vgap):使用指定的对齐方式及指定的垂直间距、水平间距创建FlowLayout布局管理器
hgap和vgap分别代表水平间距、垂直间距,为这两个参数传入整数值即可。其中align表明FlowLayout中组件的排列方向(从左向右,从右向左,从中间向两边等),该参数应该使用FlowLayout类的静态常量:FlowLayout.LEFT、FlowLayout.CENTER、Flowlayout.RIGHT
import java.awt.*;public class FlowLayoutTest{ public static void main(String[] args){ Frame f = new Frame("测试窗口"); //从左向右 f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 5)); for (int i = 0; i < 10; i++){ f.add(new Button("按钮" + i)); } f.pack(); f.setVisible(true); } }
pack()方法是Window容器提供的一个方法,该方法用于将窗口调整到最佳大小。通过Java编写图形用户界面程序时,很少直接设置窗口的大小,通常都是调用pack()方法调整到最佳大小。
BorderLayout布局管理器
BorderLayout将容器分为EAST、SOUTH、WEST、NORTH、CENTER五个区域,普通组件可以放置在这5个区域的任意一个中。
BorderLayout有两个注意点:1、当向BorderLayout的布局管理器添加组件时,需要指定要添加到哪个区域中,如果没有指定添加到哪个区域,默认添加到中间区域;2、如果向一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件。这也是为什么ScrollPane添加两个组件,只能看到一个,另一个覆盖了。
Frame、Dialog、ScrollPane默认使用BorderLayout布局管理器,BorderLayout有两个构造器:
BorderLayout():使用默认的水平间距、垂直间距创建BorderLayout布局管理器BorderLayout(int hgap, int vgap):使用指定的水平间距、垂直间距创建BorderLayout布局管理器
BorderLayout最多只能放置5个组件,但可以少于5个,少于无法区域不会空白旁边的组件会自动填充。
import java.awt.*;public class BorderLayoutTest{ public static void main(String[] args){ Frame f = new Frame("测试窗口"); f.setLayout(new BorderLayout(30, 5)); Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(new Button("EAST1"), BorderLayout.EAST); p.add(new Button("EAST2"), BorderLayout.SOUTH); p.add(new Button("EAST3"), BorderLayout.CENTER); p.add(new Button("EAST4"), BorderLayout.NORTH); p.add(new Button("EAST5"), BorderLayout.WEST); f.add(p, BorderLayout.EAST); f.add(new Button("SOUTH"), BorderLayout.SOUTH); f.add(new Button("CENTER"), BorderLayout.CENTER); f.add(new Button("NORTH"), BorderLayout.NORTH); f.add(new Button("WEST"), BorderLayout.WEST); f.pack(); f.setVisible(true); } }
GridLayout布局管理器
GridLayout布局管理器将容器分割成纵横线分割的网格,每个网格所占据的大小相同。向GridLayout布局管理器中添加组件时,默认从左向右,从上向下依次添加到每个网格中。GridLayout布局管理器中的各组件的大小由每个组件所处的区域决定(每个组件自动占满整个区域)
GridLayout有两个构造器:
1、GridLayout(int rows, int cols):采用指定的行数、列数,以及默认的横向间距、纵向间距将容器分割成多个网格2、GridLayout(int rows, int cols, int hgap, int vgap):采用指定的行数、列数,以及指定的横向间距、纵向间距将容器分割成多个网格
下面使用GridLayout和BorderLayout做计算器接口:
import java.awt.*;public class GridLayoutTest{ public static void main(String[] args){ Frame f = new Frame("Test"); Panel p1 = new Panel(); p1.add(new TextField(30)); f.add(p1, BorderLayout.NORTH); Panel p2 = new Panel(); p2.setLayout(new GridLayout(3, 5, 4, 4)); String[] name = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "-", "*", "/", "="}; for (int i = 0; i < name.length; i++){ p2.add(new Button(name[i])); } f.add(p2); f.pack(); f.setVisible(true); } }
GridbagLayout布局管理器
GridLayout布局管理器的功能最强大,但也更复杂,与GridLayout不同的是,GridBagLayout布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同,从而增加布局的灵活性。
为了处理GridBagLayout中的GUI组件大小、跨越性,Java提供了GridBagConstraints对象,该对象与特定的GUi组件关联,用于控制该GUi的大小、跨越性。
使用GridBagLayout布局管理器的步骤如下:
1、创建GridBagLayout布局管理器,并指定GUi容器使用该布局管理器
GridBagLayout gb = new GridBagLayout();container.setLayout(gb);
2.创建GridBagConstraints对象,并设置该对象的相关属性(用于设置受该对象控制的GUI组件的大小、跨越性等)
GridBagConstraints gbc = new GridBagConstraints();gbc.gridx = 2; //设置组件位于网格中的横向索引gbc.gridy = 1; //设置组件位于网格中的纵向索引gbc.gridwidth = 2; //设置组件位于网格中横向跨越多少网格gbc.gridheigth = 2; //设置组件位于网格中纵向跨越多少网格
3、调用GridBagLayout的方法建立GridBagConstraints对象和受控制组件之间的关联
gb.setConstraints(c, gbc); //组件c受gbc对象控制
4、添加组件
container.add(c);
如果需要向一个容器中添加多个GUI组件,重复步骤2~4。GridBagConstraints对象可以多次重用,所以创建一个对象即可,每次添加GUI组件前改变GridBagConstraints对象属性即可。
使用GridBagLayout布局管理器的关键在于GridBagConstraints,该类有如下属性:
1、gridx、 gridy:设置受该对象控制的GUI组件左上角所在网格的横向索引、纵向索引(GridBagLayout左上角索引为0, 0),这两个值还可以是GridBagConstraints.RELATIVE(默认值),它表明当前组件紧跟上一组件2、gridwidth、gridheigth:设置受该对象控制的GUI组件横向、纵向跨越多少个网格,两个属性默认值为1。如果设置这两个属性值为GridBagConstraints.REMAINDER,则表明受该对象控制的GUI组件横向、纵向最后一个
组件,如果这是为GridBagConstraints.RELATIVE这表明受该对象控制的GUI组件的横向、纵向倒数第二个组件3、fill:设置受该对象控制的GUI组件如何占据空白区域 ·GridBagConstraints.NONE:GUI组件不扩大 ·GridBagConstraints.HORIZONTAL:GUI组件水平扩大以占据空白区域 ·GridBagConstraints.VERTICAL:GUI组件垂直扩大以占据空白区域 ·GridBagConstraints.BOTH:GUI组件水平、垂直通知扩大占据空白区域4、ipadx、ipady:设置受该对象控制的GUI组件横向、纵向内部填充的大小,即在该组件最小尺寸基础上海需要增大多少5、insets:设置受该对象控制的GUI组件的外部填充大小,即该组件边界和显示区域边界之间的距离6、anchor:设置受该对象控制的GUI组件在其显示区域中的定位方式,定位形式如下: ·GridBagConstraints.CENTER(中间) ·GridBagConstraints.NORTH(上中) ·GridBagConstraints.NORTHWEST(左上角) ·GridBagConstraints.NORTHEAST(右上角) ·GridBagConstraints.SOUTH(下中) ·GridBagConstraints.SOUTHEAST(右下角) ·GridBagConstraints.SOUTHEAST(左下角) ·GridBagConstraints.EAST(右中) ·GridBagConstraints.WEST(左中)7、weighx、weighy:设置受该对象控制的GUI组件占据多余空间的水平、垂直增加比例,这两个值默认0,就是不占据多余空间。
import java.awt.*;public class GridBagTest{ private Frame f = new Frame("测试窗口"); private GridBagLayout gb = new GridBagLayout(); private GridBagConstraints gbc = new GridBagConstraints(); private Button[] bs = new Button[10]; public void init(){ f.setLayout(gb); for (int i = 0; i < bs.length; i++){ bs[i] = new Button("按钮" + i); } //所有组件都可以横向、纵向扩大 gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; addButton(bs[0]); addButton(bs[1]); addButton(bs[2]); //该GridBagConstraints控制的GUI组件将会成为横向最后一个组件 gbc.gridwidth = GridBagConstraints.REMAINDER; addButton(bs[3]); //该GridBagConstraints控制的GUI组件将在横向上不会扩大 gbc.weightx = 0; addButton(bs[4]); //该GridBagConstraints控制的GUI组件横跨两个网格 gbc.gridwidth = 2; addButton(bs[5]); //该GridBagConstraints控制的GUI组件横跨一个网格 gbc.gridwidth = 1; //该GridBagConstraints控制的GUI组件纵向跨两个网格 gbc.gridheight = 2; //该GridBagConstraints控制的GUI组件将会成为横向最后一个组件 gbc.gridwidth = GridBagConstraints.REMAINDER; addButton(bs[6]); gbc.gridwidth = 1; gbc.gridheight = 2; gbc.weighty = 1; addButton(bs[7]); gbc.weighty = 0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridheight = 1; addButton(bs[8]); addButton(bs[9]); f.pack(); f.setVisible(true); } private void addButton(Button button){ gb.setConstraints(button, gbc); f.add(button); } public static void main(String[] args){ new GridBagTest().init();} }
import java.awt.*;public class GridBagLayoutTest{ public static void main(String[] args){ Frame f = new Frame("Test"); GridBagLayout gb = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); f.setLayout(gb); Button[] bs = new Button[10]; for (int i = 0; i < bs.length; i++){ bs[i] = new Button("按钮" + i); //要在按钮添加之前关联组件受GridBagConstraints控制 //gb.setConstraints(bs[i], gbc); } gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gb.setConstraints(bs[0], gbc); gb.setConstraints(bs[1], gbc); gb.setConstraints(bs[2], gbc); f.add(bs[0]); f.add(bs[1]); f.add(bs[2]); gbc.gridwidth = GridBagConstraints.REMAINDER; gb.setConstraints(bs[3], gbc); f.add(bs[3]); gbc.weightx = 0; gb.setConstraints(bs[4], gbc); f.add(bs[4]); gbc.gridwidth = 2; gb.setConstraints(bs[5], gbc); f.add(bs[5]); gbc.gridwidth = 1; gbc.gridheight = 2; gbc.gridwidth = GridBagConstraints.REMAINDER; gb.setConstraints(bs[6], gbc); f.add(bs[6]); gbc.gridwidth = 1; gbc.gridheight = 2; gbc.weighty = 1; gb.setConstraints(bs[7], gbc); f.add(bs[7]); gbc.weighty = 0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridheight = 1; gb.setConstraints(bs[8], gbc); gb.setConstraints(bs[9], gbc); f.add(bs[8]); f.add(bs[9]); f.pack(); f.setVisible(true); } }
建议使用GridBagTest中的方法更方便快捷添加组件。
CardLayout布局管理器
CardLayout布局管理器以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成 一叠卡片,每次只有最上面的那个conponent才可见。
CardLayout提供了两个构造器及几个方法:
CardLayout():创建默认的CardLayout布局管理器CardLayout(int hgap; int vgap):通过指定卡片与容器左右边界的间距、上下边距创建CardLayout布局管理器常用方法:first(Container target):显示target容器中的第一张卡片last(Container target):显示target容器中的最后一张卡片previous(Container target):显示target容器中的前一张卡片next(Container terget):显示target容器中的后一张卡片show(Container target, String name):显示target容器中指定名字的卡片
public class CardLayoutTest{ Frame f = new Frame("Test"); String[] names = {"第一张", "第二张", "第三张", "第四张", "第五张"}; Panel p1 = new Panel(); public void init(){ final CardLayout c = new CardLayout(); p1.setLayout(c); for (int i = 0; i < names.length; i++){ //add(添加组件名,组件) p1.add(names[i], new Button(names[i])) } Panel p = new panel(); ActionListener listener = e ->{ switch(e.getActionCommand()){ case "上一张": c.previous(p1); break; case "下一张": c.next(p1); break; case "第一张": c.first(p1); break; case "最后一张": c.last(p1); break; case "第三张": c.show(p1, "第三张"); break; } }; //控制显示上一张的按钮 Button previous = new Button("上一张"); previous.addActionListener(listener); //控制显示下一张的按钮 Button next = new Button("下一张"); next.addActionListener(listener); ... } }
绝对定位
Java可以对GUI组件进行绝对定位,在Java容器中采用绝对定位步骤:
1、将Container的布局管理器设置成null:setLayout(null);
2、向容器中添加组件时,先调用setBounds()或setSize()方法来设置组件的大小、位置,或者直接创建GUI组件时通过构造参数指定该组件的大小、位置,然后会将组件添加到容器中。
不过采用绝对定位可能导致该GUI界面失去跨平台特性。
BoxLayout布局管理器
BoxLayout可以在垂直和水平两个方向摆放GUi组件,BoxLayout提供了一个简单的构造器:
BoxLayout(Container target, int axis):指定创建基于terget容器的BoxLayout布局管理器,该布局管理器的组件按axis方向排列,其中axis有BoxLayout.X_AXIS(横向)和BoxLayout.Y_AXIS(纵向)两个方向。
import javax.swing.*;import java.awt.*;public class BoxLayoutTest{ Frame f = new Frame("Test"); public void init(){ f.setLayout(new BoxLayout(f, BoxLayout.X_AXIS)); f.add(new Button("第一个按钮")); f.add(new Button("第二个按钮")); f.pack(); f.setVisible(true); } public static void main(String[] args){ new BoxLayoutTest().init(); } }
BoxLayout通常和Box容器结合使用,Box容器默认使用BoxLayout布局管理器,Box提供了如下两个静态方法创建Box对象:
createHorizontalBox():创建一个水平排列组件的Box容器
CreateVerticalBox():创建一个垂直排列组件的Box容器
Box容器还提供了5个静态方法:
createHorizontalGlue():创建一条水平Glue(可在两个方向上同时拉伸的间距)createVerticalGlue():创建一条垂直Glue(可在两个方向上同时拉伸的间距)createHorizonalStrut(int width):创建一条指定宽度的水平Strut(可在垂直方向上拉伸的间距)createVerticalStrut(int height):创建一条指定高度的垂直Strut(可在水平方向上拉伸的间距)createRigidArea(Dimension d):创建指定宽度、高度的RigidArea(不可拉伸间距)
Glue可以在两个方向同时拉伸,Strut只能在一个方向拉伸,RigidArea不能拉伸。
AWT常用组件
基本组件
Button:按钮,可接受单击操作Canvas:用于绘图画布Checkbox:复选框组件(也可编程单选框组件)CheckboxGroup:用于将多个Checkbox组件合成一组,一组Checkbox组件只有一个可以被选中,全部变成单选框组件Choice:下拉式选择框组件Frame:窗口,在GUI程序里通过该类创建窗口Label:标签类,用于防止提示性文本Panel:不能单独存在基本容器类,必须放在其他容器中Scrollbar:滑动条组件ScrollPane:带水平及垂直滚动条的容器组件TextArea:多行文本域TextField:单行文本框
List:列表框组件,可以添加多项条目
import java.awt.*;import javax.swing.*;public class CommonComponment{ Frame f = new Frame("Test"); Button ok = new Button("确认"); CheckboxGroup cbg = new CheckboxGroup(); Checkbox male = new Checkbox("男", cbg, true); Checkbox female = new Checkbox("女", cbg, false); Checkbox married = new Checkbox("是否已婚?" ,false); Choice colorChooser = new Choice(); List colorList = new List(6, true); TextArea ta = new TextArea(5, 20); TextField name = new TextField(50); public void init(){ colorChooser.add("红色"); colorChooser.add("绿色"); colorChooser.add("蓝色"); colorList.add("红色"); colorList.add("绿色"); colorList.add("蓝色"); //创建一个装载了文本框、按钮的Panel Panel bottom = new Panel(); bottom.add(name); bottom.add(ok); f.add(bottom, BorderLayout.SOUTH); //创建一个装载下拉选择框、三个Checkboxd panel Panel checkPanel = new Panel(); checkPanel.add(colorChooser); checkPanel.add(male); checkPanel.add(female); checkPanel.add(married); //创建一个垂直排列组件的Box,盛装多行文本域、Panel Box topLeft = Box.createVerticalBox(); topLeft.add(ta); topLeft.add(checkPanel); Box top = Box.createHorizontalBox(); top.add(topLeft); top.add(colorList); f.add(top); f.pack(); f.setVisible(true); } public static void main(String[] args){ new CommonComponment().init(); } }
对话框(Dialog)
Dialog是Window的子类,是一个容器类,属于特殊组件。对话框是可以独立存在的顶级窗口,因此用法与普通窗口的用法几乎完全一样,但对话框有如下两点需要注意:
1、对话框通常依赖于其他窗口,就是通常有一个parent窗口;
2、对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开之后,该模式对话框总是位于它依赖的窗口之上;在模式对话框被关闭之前,它依赖的窗口无法获得焦点。
对话框有多个重载的构造器,它的构造器可能有如下三个参数:
1、owner:指定该对话框所依赖的窗口,既可以是窗口,也可以是对话框;
2、title:指定该对话框的窗口标题
3、modal:指定该对话框是否是模式的,可以是true或false
import java.awt.*;import javax.swing.*;public class DialogTest{ Frame f = new Frame("Test"); //owner = f; title = "模式对话框"; modal = true Dialog d1 = new Dialog(f, "模式对话框", true); Dialog d2 = new Dialog(f, "非模式对话框", false); Button b1 = new Button("打开模式对话框"); Button b2 = new Button("打开非模式对话框"); public void init(){ d1.setBounds(20, 30, 300, 400); d2.setBounds(20, 30, 300, 400); b1.addActionListener(e -> d1.setVisible(true)); b2.addActionListener(e -> d2.setVisible(true)); f.add(b1); f.add(b2, BorderLayout.SOUTH); f.pack(); f.setVisible(true); } public static void main(String[] args){ new DialogTest().init(); } }
如果主程序需要对话框接收输入值,则应该把该对话框设置成模式对话框。
Dialog类有一个子类FileDialog,代表一个文件对话框,用于打开或保存文件。FileDialog提供了几个构造器,分别支持parent、title和mode三个构造器,其中parent、title指定文件对话框所属父窗口和标题,而mode指定该窗口打开文件或者保存文件,该参数有两个:FileDialog.LOAD,FileDialog.SAVE。
FileDialog提供了两个方法:
getDirectory():获取被打开/保存文件的绝对路径
getFile():获取FileDialog被打开/保存文件名
import java.awt.*;public class FileDialogTest{ Frame f = new Frame("Test"); FileDialog d1 = new FileDialog(f, "选择需要打开的文件", FileDialog.LOAD); FileDialog d2 = new FileDialog(f, "选择需要保存的文件", FileDialog.SAVE); Button b1 = new Button("打开文件"); Button b2 = new Button("保存文件"); public void init(){ b1.addActionListener(e -> { d1.setVisible(true); System.out.println(d1.getDirectory() + d1.getFile()); }); b2.addActionListener(e ->{ d2.setVisible(true); System.out.println(d2.getDirectory() + d2.getFile()); }); f.add(b1); f.add(b2, BorderLayout.SOUTH); f.pack(); f.setVisible(true); } public static void main(String[] args){ new FileDialogTest().init(); } }
事件处理
AWT编程中,所有时间必须由特定对象(时间监听器)来处理。
为了使图形界面能够接收用户的操作,必须给各个组件加上事件处理机制。
在时间处理过程中,主要涉及三个对象:
1、Event Source(事件源):事件发生的场所,通常就是各个组件,例如:按钮、窗口等。
2、Event(事件):事件封装了GUI组件上发生的特定事情(通常就是一次用户操作),如果程序需要获得GUI组件上所发生的事件相关信息,都通过Event对象获得。
3、Event Listener(事件监听器):负责监听事件源所发生的事件,并对各种事件作出响应处理。
Java是面向对象的编程语言,方法不能独立存在,因此必须以类的形式来组织这些方法,所以事件监听器的核心就是它所包含的方法——这些方法也被称为事件处理器。
AWT的事件处理机制是一种委派式事件处理方式—普通组件(事件源)将事件的处理工作委托给特定的喜爱你过(事件监听器);当该事件源发生指定事件时,就通过所委托的事件监听器,由事件监听器来处理这个事件。
同一事件源可能发生多种事件,委派式事件处理方式可以把事件源上可能发生的不同事件分别授权给不同的事件监听器来处理,同时也可以让一类事件都是用同一事件监听器来处理。
事件处理流程:将事件监听器注册到事件源——外部动作触发事件——生成事件对象——触发事件监听器——调用事件处理器作出响应
import java.awt.*;import java.awt.event.*;public class EventTest{ Frame f = new Frame("测试窗口"); Button ok = new Button("确定"); TextField tf = new TextField(30); public void init(){ //注册事件监听器 ok.addActionListener(new okListener()); f.add(tf); f.add(ok, BorderLayout.SOUTH); f.pack(); f.setVisible(true); } //定义事件监听器类 class okListener implements ActionListener{ //事件处理器,用于相应特定的事件 public void actionPerformed(ActionEvent e){ System.out.println("用户点击了ok按钮"); tf.setText("Hello World"); } } public static void main(String[] args){ new EventTest().init(); } }
实现AWT事件处理机制的步骤如下:
1、实现事件监听器类,该监听器类是一个特殊的Java类,必须实现一个XxxListener接口;
2、创建普通组件(事件源),创建事件监听器对象;
3、调用addXxxListener()方法将事件处理器对象注册给普通组件(事件源)。
AWT事件机制涉及三个成员:事件源、事件和事件监听器,事件由系统自动产生,无法关心。实现事件监听器是整个事件处理的核心。
事件处理器必须实现时间监听接口,AWT提供了大量的事件监听器接口用于实现不同类型的事件监听器。AWT的事件类都是AWTEvent的子类,AWTEvent是EventObject的子类。
EventObject类代表更广义的事件对象,包括Swing组件上所触发的事件、数据库连接所触发的事件等。
AWT事件分为两大类:低级事件和高级事件
低级事件时指基于特定动作的事件。比如:进入、点击、位置发生移动等动作的鼠标事件。当组件得到焦点、失去焦点时触发的事件。
高级事件(语义事件)
高级事件是基于予以的事件,它可以不和特定的动作相关联,而依赖于触发此事件的类。比如,在TextField中按Enter键会触发ActionEvent事件,在滑动条上移动滑块会触发AdiustmentEvent事件,选中项目列表的某一项会触发ItenEvent事件。
1、ActionEvent:动作事件,当按钮、菜单项被单击,在TextField中按Enter就触发该事件;
2、AdjustmentEvent:调节事件,在滑动条上移动滑块以调节数值时触发该事件;
3、ItemEvent:选项事件,当用户选中某项,或取消选中某项触发该事件;
4、TextEvent:文本事件,当文本框、文本域里的文本发生改变时触发该事件。
大部分的时候程序无须监听每个窗口的每个动作,只需要用户点击窗口中的“X”按钮提供相应即可,但是实现WindowListener接口,实现该接口就不得不实现每个抽象方法,这就蛋疼了。为此,AWT提供了事件适配器。事件适配器是监听器接口的空实现——事件适配器实现了监听器接口,并为该接口里的每个方法都提供了实现,这种实现是一种空实现(方法体内没有任何代码)。当需要创建监听器时,可以通过继承事件适配器,而不是实现监听器接口。继承事件适配器,程序自己的监听器无须实现监听器接口里的每个方法,只需要重写自己感兴趣的方法,从而简化时间监听器的实现类代码。
如果监听器接口只有一个方法,则该监听器接口无须提供适配器,该监听器别无选择,只能重写该方法。
import java.awt.*;import java.awt.event.*;//继承事件适配器class MyListener extends WindowAdapter{ public void windowClosing(WindowEvent e){ System.exit(0); } public void windowActivated(WindowEvent e){ } }public class FrameTest{ public static void main(String[] args){ Frame f = new Frame("创建窗口"); //指定具有滚动条 ScrollPane p = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); p.add(new Button("单击我")); p.add(new TextField(20)); f.addWindowListener(new MyListener()); f.add(p); f.setBounds(30, 30, 250, 250); f.setVisible(true); } }
使用内部类实现监听器
事件监听器是一个特殊的Java对象,实现事件监听器对象有如下几种形式:
1、内部类形式,将事件监听器类定义成当前类的内部类
2、外部类形式:将事件监听器类定义成一个外部类
3、类深深作为事件监听器类:让当前类本身实现监听器接口或继承事件适配器
4、匿名内部类:使用匿名内部来创建事件监听器对象
public class FrameTest extends WindowAdapter{ public static void main(String[] args){ Frame f = new Frame("创建窗口"); ScrollPane p = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); p.add(new Button("单击我")); p.add(new TextField(20)); //使用内部类实现监听器 f.addWindowListener(new MyListener(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); f.add(p); f.setBounds(30, 30, 250, 250); f.setVisible(true); } }
如果事件监听器接口只包含一个方法,通过会使用Lambda表达式代替匿名内部类创建监听器对象。如果通过继承事件适配器创建事件监听器,就无法使用Lambda表达式了。
AWT菜单
AWT菜单有几个类组成:
1、MenuBar:菜单条、菜单的容器;
2、Menu:菜单组件,菜单项的容器。它也是MenuItem的子类,所以可作为菜单项使用
3、PopupMenu:上下文菜单组件(右键菜单组件)
4、MenuItem:菜单组件
5、CheckboxMenuItem:复选框菜单项组件
6、MenuShortcut:菜单快捷键组件
MenuBar和Menu都实现了菜单容器接口,所以MenuBar可用于盛装Menu,而Menu可用于盛装MenuItem(包括Menu和CheckboxMenuItem两个子类对象)。Menu还有一个子类:PopupMenu,代表上下文菜单,上下文菜单无须使用MenuBar盛装。
MenuShortcut ms = new MenuShortcut(KeyEvent.vk_A) //ctrl + AMenuShortcut ms = new MenuShortcut(KeyEvent.vk_A, true) //ctrl + shift + A
创建右键菜单:
1、创建PopupMenu的实例;
2、创建多个MenuItem的多个实例,依次将这些实例加入PopupMenu中;
3、将PopupMenu加入到目标组件中;
4、为需要出现上下文菜单的组件编写鼠标监听器,当用户释放鼠标右键时弹出右键菜单。
在AWT中绘图
有时候需要动态向客户端生成各种图形、图表,比如验证码之类的,就需要利用AWT的绘图功能。
在Componment类里提供了和绘图有关的三个方法:
paint(Graphics g):绘制组件的外观
update(Graphics g):调用paint()方法,刷新组件外观
repaint():调用update()方法,刷新组件外观
Container类中的update()方法先以组件的背景色填充整个组件区域,然后调用paint()方法重画组件:
public void update(Graphics g){ if (isShowing()){ if (!(peer instanceof LightweightPeer)){ g.clearRect(0, 0, width, height); } paint(g); } }
普通组件的update()方法则直接调用paint()方法:
public void update(Graphics g){ paint(g); }
程序不应该主动调用组件的paint()和update()方法,这两个方法都由AWT系统负责调用。如果需要AWT系统重新绘制该组件。则调用该组件的repaint()方法。而paint()和update()方法通常被重写。
重写paint()和update()方法,该方法里包含一个Graphics类型的参数。通过该参数就可以实现绘图功能。
Graphics是一个抽象的画笔对象,Graphics可以在组件上绘制丰富多彩的集合图形和位图。Grapics提供了setColor()和setFont()两个方法设置画笔的颜色和字体(仅绘制字符串时有效),其中setColor()方法需要传入一个Color参数,它可以使用RGB、CMYK等方式设置一个颜色,setFont(0方法传入一个Font参数,Font参数需要指定字体名、字体样式、字体大小三个属性。AWT普通组件也可以通过Color()和Font()两个方法改变它的前景色和字体。所有组件都有一个setBackground()方法设置组件的背景色。
import java.awt.*;import java.awt.event.*;import java.util.Random;class MyListener extends WindowAdapter{ public void windowClosing(WindowEvent e){ System.exit(0); } }public class CanvasTest{ private final String RECT_SHAP = "rect"; private final String OVAL_SHAP = "oval"; Frame f = new Frame("测试窗口"); Button rect = new Button("绘制矩形"); Button oval = new Button("绘制椭圆"); private String shap = ""; private MyCanvas drawArea = new MyCanvas(); public void init(){ Panel p = new Panel(); rect.addActionListener(e -> { shap = RECT_SHAP; drawArea.repaint(); }); oval.addActionListener(e -> { shap = OVAL_SHAP; drawArea.repaint(); }); p.add(rect); p.add(oval); drawArea.setPreferredSize(new Dimension(250, 180)); f.addWindowListener(new MyListener()); f.add(drawArea); f.add(p, BorderLayout.SOUTH); f.pack(); f.setVisible(true); } class MyCanvas extends Canvas{ public void paint(Graphics g){ Random rand = new Random(); if (shap.equals(RECT_SHAP)){ //设置画笔颜色 g.setColor(new Color(220, 100, 80)); g.drawRect(rand.nextInt(200), rand.nextInt(120), 40, 60); } if (shap.equals(OVAL_SHAP)){ g.setColor(new Color(80, 100, 200)); g.fillOval(rand.nextInt(200), rand.nextInt(120), 50, 40); } } } public static void main(String[] args){ new CanvasTest().init(); } }
也可用于开发一些动画。所谓动画,就是间隔一定时间(通常小于0.1秒)重新绘制图像,两次绘制图像的差距较小。为了实现间隔一定的时间重新调用组件的repaint()方法,可以借助于Swing提供的Timer类:
Timer(int delay, ActionListener listener):每隔delay毫秒,系统会自动触发ActionListener监视器里的事件处理器()actionPerformed()方法)
处理位图
AWT允许在组件上绘制位图,Grapics提供了drawImage方法用于绘制位图,该方法需要一个Image参数——代表位图,通过该方法就可以绘制出指定的位图。
AWT