1、单元单元 15swing 事件处理事件处理单元目标 理解 Java 委托事件处理机制; 了解常用的事件类、处理事件的接口及接口中的方法; 掌握编写事件处理程序的基本方法;熟练掌握对按钮的 ActionEvent 动作事件的处理。学习任务1.任务描述实现计算器的计算功能。在上个任务的基础上,添加用户操作响应代码即事件处理代码,完成计算功能。2.运行结果知识准备15.1 Java 事件事件是 EventObject 子类的对象,描述在某个时间,某个对象上,发生了某件事情。通过鼠标、键盘与 GUI 界面直接或间接交互都会生成事件。如:按计算器事件处理计算器事件处理下一个按钮、通过键盘输入一个字符、选
2、择列表框中的一项、点击一下鼠标等。事件不局限于界面操作,比如网络连接或断开等都可看作是事件。事件源是生成事件对象的对象,用事件对象来描述自身状态的改变,即在某时刻,其上发生了什么事情。可以通过回调规定接口对象,将事件发送给其他对象,以使其他对象对事件作出反应成为可能。 监听器是对某类事件感兴趣, 并希望做出响应的对象,必须实现规定接口,此类接口称为监听器接口。事件处理的关键步骤:1.实现监听器接口,定义监听器类,在接口规定方法内实现事件处理逻辑;2.创建监听器对象,将监听器添加到事件源;3.出发事件,事件源回调监听器中相关方法。例如,当用户用鼠标点击一个按钮 jb(JButton 的对象)时,
3、就会产生一个ActionEvent 事件,此时按钮 jb 就是事件源。如果要在计算器窗口类中响应按钮点击事件,计算器窗口就是监听器。为了能够作为 ActionEvent 事件的监听器,Calculator类 要 实 现 接 口ActionListener , 添 加publicvoidactionPerformed(ActionEvent e) 方法, 并在该方法中编写按钮点击后要执行的代码。接口 ActionListener 定义如下:Interface ActionListenervoid actionPerformed(ActionEvent e);然后将监听器添加到事件源 jb.add
4、ActionListener(this),这里 this 代表的是 Calculator 类的当前对象,就是计算器窗口对象。ActionEvent 的主要方法:String getActionCommand(); 获取事件的命令字符串,对按钮而言,该方法返回按钮上显示的文字。通过 getActionCommand 返回结果可以知道用户点击了哪一个按钮。public Object getSource(); 该方法获取事件源对象引用。 如果界面中有多个按钮, 通过将 getSource 结果和每一个按钮对象引用比较, 可以知道用户点击了哪一个按钮引发的本次事件。15.2 Java 事件处理机制要理
5、解事件处理机制, 必须学会站在组件开发者和组件使用者这两个不同的角度来思考问题。事件处理机制的任务是当组件发生某种事件时,要设法通知组件使用者,并允许组件使用者做出个性化的处理。定义组件的目的就是在组件设计完成后到处可以重复使用此组件。因此,组件设计在前,组件使用在后。在定义组件类时,我们并不知道将来谁要使用此组件,从而也就无法确定谁要接收并处理此组件产生的事件。现在的任务就是要找一种办法,将事件消息正确的传递给将来的不确定的组件使用者。如图 4-11 所示:图 4-11 事件处理示意图事件处理机制需要考虑的问题,有以下三个方面:1要接收消息的对象:消息的接收者在使用组件时,先向该组件进行注册
6、。为此,组件应实现注册方法。比如 JTextField 类的 addActionListener()方法。2. 消息传递方法:向消息接收对象传递消息最根本的方法就是调用消息接收对象的一个方法,并通过方法参数将事件相关数据传递给消息接收对象。而不管消息接收对象是何种类型,组件调用的方法必须是一致的,因为组件无法针对每一个消息接收对象进行特殊的方法调用。对组件来说,最好所有消息接收对象看起来都是一样的,都是同一种类型,都支持相同的方法。那么现在的问题就变成: 如何保证所有消息接收对象都都是同一种类型而又能进行各自不同的事件处理呢?如何约束消息接收者的行为?要保证所有消息接收对象都是同一种类型,一种
7、方法就是定义一个类,要求所有消息接收对象都由此类的子类创建,这不是一个好办法,因为这限制了消息接收对象的继承层次。更好的解决方案是使用接口。即将事件处理方法,也就是组件向消息接收对象传递消息要调用的方法,定义在一个接口里。 然后强制注册对象必须实现此接口。 事先规定对象方法的形式,而不关心其具体实现,这正是接口的优势所在。这种方法,不管注册对象是从哪个类派生的,从而保证了消息接收对象类层次定义的自由。3. 传递数据的方法:一种方法是直接通过传递方法的参数。另一种方法,也是现在 Java 采用的面向对象的方法定义一个类来描述事件,当具体事件产生时,则创建一个此事件类的对象,将该对象作为参数进行传
8、递。以上事件处理机制实际上采用了一种应用非常普遍的接口回调思想。 其基本过程是:规定回调接口;实现回调接口;回调接口对象注册;接口回调。定义回调接口的对象,往往是要提供某种服务,但接受服务的对象又不能事先确定。而要实现这种服务,服务对象又必须调用客户对象的方法。一旦遇到这种情况,就可使用接口回调。接口回调的应用不局限于事件处理。比如,网络通讯中就经常使用。现实生活中这样的例子也有很多,比如企业要先注册,然后实现一些标准接口如账目,然后工商税务就可对其进行税收管理等。15.3 Java 事件体系结构Java 事件体系结构如图 4-12 所示,所有事件共同的父类是 EventObject。Java
9、 把事件类大致分为两种:语义事件(semantic events)与底层事件(low-levelevents)。语义事件直接继承自 AWTEvent,如 ActionEvent、AdjustmentEvent与 ComponentEvent 等。底层事件则是继承 自 ComponentEvent 类,如ContainerEvent、FocusEvent、WindowEvent 与 KeyEvent 等。Java 事件类的说明详见表 4-5。图 4-12 事件类体系图表 4-5 Java 事件类的相关说明事件类事件类说明说明事件源事件源ActionEvent通常按下按钮, 双击列表项或选中一个菜
10、单项时,就会生成此事件。Button、List、MenuItem、TextFieldAdjustmentEvent操纵滚动条时会生成此事件。ScrollbarComponentEvent当一个组件移动、隐藏、调整大小或成为可见时会生成此事件。ComponentItemEvent单击复选框或列表项时, 或者当一个选择框或一个可选菜单的项被选择或取消时生成此事件。Checkbox、CheckboxMenuItem、Choice、ListFocusEvent组件获得或失去键盘焦点时会生成此事件。 ComponentKeyEvent接收到键盘输入时会生成此事件。ComponentMouseEvent拖
11、动、移动、单击、按下或释放鼠标或在鼠标进入或退出一个组件时,会生成此事件。ComponentContainerEvent将组件添加至容器或从中删除时会生成此事件。ContainerTextEvent在文本区或文本域的文本改变时会生成此事件 。TextField、TextAreaWindowEvent当一个窗口激活、关闭、失效、恢复、最小化、打开或退出时会生成此事件。Window15.4 Java 事件监听器和监听方法j java.awt.event 包中还定义了 11 个监听者接口,如表 4-6 所示,每个接口内部包含了若干处理相关事件的抽象方法。一般说来,每个事件类都有一个监听者接口与之相对
12、应, 而事件类中的每个具体事件类型都有一个具体的抽象方法与之相对应,当具体事件发生时,这个事件将被封装成一个事件类的对象作为实际参数传递给与之对应的具体方法,由这个具体方法负责响应并处理发生的事件。例如 ActionListener,这个接口定义了抽象方法:public voidactionPerformed(ActionEvent e)。 凡是要处理 ActionEvent 事件的类都必须实现ActionListener 接口,并重写相应的 actionPerformed()方法表 4-6 Java 事件监听器和监听方法事件监听器事件监听器方法方法ActionListeneractionPe
13、rformedAdjustmentListeneradjustmentValueChangedComponentListenercomponentResized、componentMoved、componentShown、componentHiddenContainerListenercomponentAdded、componentRemovedFocusListenerfocusLost、focusGainedItemListeneritemStateChangedKeyListenerkeyPressed、keyReleased、keyTypedMouseListenermouseClic
14、ked 、 mouseEntered 、 mouseExited 、mousePressed、mouseReleasedMouseMotionListenermouseDragged、mouseMovedTextListenertextChangedWindowListenerwindowActivated、windowDeactivated、windowClosed、windowClosingwindowIconified、 windowDeiconified、 windowOpened15.4.1 焦点事件焦点事件 FocusEvent。任何 GUI 对象的获得或失去焦点都被视为焦点事件,
15、 并且事件源必须向事件监听器通知事件对象已失去或已获得焦点。焦点监听器需要实现两个 方法:focusGained 和 focusLost。对组件输入数据要进行错误检查或范围校验时, 对焦点的捕捉就显得尤其重要。其特有方法如下:Component getOppositeComponent() 返回焦点变化事件中的另一组件boolean isTemporary() 说明此事件是临时还是永久的String paramString()获取说明此事件的一字符串15.4.2 窗口事件窗口事件 WindowEvent:当一个窗口被激活、禁止、关闭、正在关闭、最小化、恢复、打开时将生成窗口事件。窗口事件 Wi
16、ndowEvent 有七种类型,在WindowEvent 类中定义了用来表示它们的整数常量,意义如下所示:WINDOW_ACTIVATED 窗口被激活;WINDOW_CLOSED 窗口已经被关闭;WINDOW_CLOSING用户要求窗口被关闭; WINDOVV_DEACTIVATED 窗口被禁止;WINDOW_DEICONIFIED 窗口被恢复;WINDOW_ICONIFIED 窗口被最小化; WINDOW_OPENED 窗口被打开。 使用接口 WindowListener 对相应的 事 件 进 行 监 听 处 理 。 需 要 实 现 的 方 法 如 下 : windowActivated 、
17、windowDeactivated、windowClosing、 windowClosed、windowDeiconified、windowIconified、windowOpened。WindowListener 接口对 WindowEvent 作监听处理,在这个接口中定义了七个方法:当一个窗口被激活或禁止时,windowActivated()方法和 windowDeactivated()方法将相应地被调用;如果一个计算器事件处理窗口被最小化,windowIconified()方法将被调用;当一个窗口被恢复时,windowDeIconified() 方 法 将 被 调 用 ; 当 一 个 窗
18、 口 被 打 开 或 关 闭 时 ,windowOpened()方法或 windowClosed()方法将相应地被调用; 当一个窗口正在被关闭时,windowClosing()方法将被调用。WindowEvent 的特有方法如下:int getNewState() WINDOW_STATE_CHANGED 事件的新状态int getOldState() WINDOW_STATE_CHANGED 事件的原状态WindowgetOppositeWindow() 焦点或激活事件的另一影响窗口WindowgetWindow() 事件创建窗口15.4.3 文字事件文字事件使用类 TextEvent 来表
19、示,使用接口 TextListener 对相应的事件进行监听处理。TextEvent 文字事件,当组件对象中的文字内容改变时,便会触发此事件。TextEvent 事件会发生在 JTextField 和 JTextArea 两种对象上。TextListener 接口对 TextEvent 作监听处理,当单行文本框 JTextField 或多行文本框 JTextArea 中的文本发生变化时,textValueChanged()方法将被调用。15.4.4 键盘事件在按下或释放键盘上的一个键时,将生成键盘事件。处理键盘事件的程序要实现在 java.awt.event 包中定义的接口 KeyListen
20、er,在这个接口中定义了未实现的键盘事件处理方法。如果程序需要处理特殊的键,如方向键,需要通过调用keyPressed( ) 方法来处理。键盘事件处理方法为:public void KeyPressed(KeyEvent e)处理按下键。public void KeyReleased(KeyEvent e)处理松开键。public void KeyTyped(KeyEvent e)处理敲击键盘。KeyEvent 事件类的主要方法有:puhlic char getKeyChar():用来返回一个被输入的字符public StringgetKeyText():用来返回被按键的键码public St
21、ringgetKeyModifiersText():用来返回修饰键的字符串KevListener 接口对 KevFvent 作监听处理,在这个接口中定义了三个方法:当一个键被按下和释放时,kevPressed()方法和 keyReleased()方法将被调用;当一个字符被输入时,keyTyped()方法将被调用。public int getKeyCode()返回与此事件中的键相关联的整数 keyCode。KeyEvent 类包含用来表示按下或点击的键的常量键码。keyCode 是每个按键的编码,JDK 帮助中可以查到每个按键对应的键码常量,如 A 对应于 VK_A。15.4.5 鼠标事件任何时
22、候移动、单击、按下或释放鼠标,都会生成鼠标事件 MouseEvent。鼠 标 事 件 对 应 两 个 接 口 : MouseListener 和 MouseMotionListener 。MouseListener 共有五个方法,主要用来实现鼠标的单击事件(用于处理组件上的鼠标按下、释放、单击、进入和离开事件) ;接口 MouseListener 中的方法为:public void mousePressed(MouseEvent e)处理按下鼠标左键public void mouseClicked(MouseEvent e)处理鼠标单击public void mouseReleased(Mou
23、seEvent e)处理鼠标按键释放public void mouseEntered(MouseEvent e)处理鼠标进入当前窗口public void mouseExited(MouseEvent e)处理鼠标离开当前窗口MouseMotionListener 有两个方法。public void mouseDragged(MouseEvent e)处理鼠标拖动public void mouseMoved(MouseEvent e)处理鼠标移动对应上述接口,对应的注册监听器的方法是 addMouseListener()和addMouseMotionListener()。MouseEvent
24、事件类中,有四个最常用的方法: int getx():返回事件发生时,鼠标所在坐标点的 x 坐标 int gety():返回事件发生时,鼠标所在坐标点的 y 坐标 int getclickCount():返回事件发生时,鼠标的点击次数 int getButton():返回事件发生时,哪个鼠标按键更改了状态当鼠标在同一点被按下并释放(单击)时,mouseClicked()方法将被调用;当鼠标进入一个组件时,mouseEntered()方法将被调用。当鼠标离开组件时,mouseExited()方法将被调用: 当鼠标被按下和释放时,相应的 mousePressed()方法和 mouseRelease
25、d()方法将被调用。当鼠标被拖动时,mouseDragged()方法将被连续调用;当鼠标被移动时,mouseNloved()方法将被连续调用。MouseEvent 的特有方法: int getButton()用于获取鼠标按键信息; int getX()、int getY()用于获取鼠标坐标位置。按键常量定义 BUTTON1、BUTTON2、BUTTON3 分别代表鼠标的三个按键(有的鼠标只有两个按键) 。例如:public void mouseClicked(MouseEvent m)int x = m.getX(); /获得点击鼠标时鼠标指针的 x 及 y 坐标int y = m.getY(
26、);int clickCount = m.getClickCount(); /确定单击和双击if(clickCount = 2)Graphics g = getGraphics();g.drawString(鼠标双击!, x, y);g.dispose();任务实施1. 实现思路修改 Calculator 类定义使其实现 ActionListener 接口,在 actionPerformed方法中添加事件处理代码,并且为每个按钮添加 this(代表当前窗口对象)作为监听器。在任务二中 Calculator 类的代码上,做如下修改:(1)导入事件处理相关包 java.awt.event.*(2)
27、修改 Calculator 类使其实现接口 ActionListener(3)增加 actionPerformed 方法, 编写按钮点击处理代码, 实现计算功能(4)为每一个按钮对象添加当前 Calculator 类对象(this)作为监听器2. 程序代码/省略任务二中的相关代码省略任务二中的相关代码public class Calculator extends JFrame implements ActionListener Calculator()/ 构造方法增加橙色代码JButton jb;for(int i=1;i= 0 & pareTo(9) =0)else if(cmd.equal
28、s(.)else if(cmd.equals(+) | cmd.equals(-) | cmd.equals(*) |cmd.equals(/)else if(cmd.equals(=)/点击= 进行计算calculate();任务拓展常用事件举例(加点说明,其他时间)1.鼠标产生的事件import java.awt.*;import java.applet.Applet;public classCountClickextends Appletint CurrentMarks=0;public boolean mouseDown(Eventevt,intx,inty)CurrentMarks+
29、;repaint();return true;public void paint(Graphics g) g.drawString( +CurrentMarks,10,10);2.键盘产生的事件计算器事件处理例:显示用户按下的字母键内容import java.applet.Applet;import java.awt.*; char Presskey;public boolean keyDown(Event evt, int key) Presskey=(char)key;repaint(); return true;public void paint(Graphics g) g.drawSt
30、ring(Presskey,10,10); 任务实训1.实训目的 理解 Java 委托事件处理机制; 了解常用的事件类、处理事件的接口及接口中的方法; 掌握编写事件处理程序的基本方法; 熟练掌握 ActionEvent 事件的处理。2.实训内容利用 Java Swing 技术设计一个 Email 邮箱地址注册的图形用户界面应用程序,运行结果如图 4-3-1 所示。图 4-3-1 Email 注册当用户输入完成后单击立即注册,判断密码和确认密码是否一致,如果一致在立即注册按钮的上方显示用户输入的邮件地址,运行结果如图 4-3-2 所示。计算器事件处理计算器事件处理图 4-3-2 立即注册信息合法当用户输入完成后单击立即注册,判断密码和确认密码是否一致,如果不一致在立即注册按钮的上方显示“密码不正确” ,运行结果如图 4-3-3 所示。图 4-3-3 立即注册信息不合法利用 Java Swing 技术设计一个 Email 注册页面,要求不管是否调整窗口大小,最终的运行界面效果一致。运行结果如图所示。