您的位置 首页 java

Java编程事件处理机制分析

java 中的事件机制的参与者有3种角色:

1.event object:事件状态对象,用于listener的相应的方法之中,作为参数,一般存在与listerner的方法之中

2.event source:具体的事件源,比如说,你点击一个button,那么button就是event source,要想使button对某些事件进行响应,你就需要注册特定的listener。

3.event listener:对每个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中,这个接口要继承 java.util.EventListener。 实现了事件监听者接口中一些或全部方法的类就是事件监听者。

伴随着事件的发生,相应的状态通常都封装在事件状态对象中,该对象必须继承自java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。发出某种特定事件的事件源的标识是:遵从规定的设计格式为事件监听者定义注册方法,并接受对指定事件监听者接口实例的引用。

具体的对监听的事件类,当它监听到event object产生的时候,它就调用相应的方法,进行处理。

先看看jdk提供的event包:

public interface EventListener:所有事件侦听器接口必须扩展的标记接口。

public class EventObject extends Object implements Serializable

所有事件状态对象都将从其派生的根类。 所有 Event 在构造时都引用了对象 “source”,在逻辑上认为该对象是最初发生有关 Event 的对象。

(1)通过DoorEvent.java文件创建DoorEvent类,这个类继承EventObject。

/**

* 定义事件对象,必须继承EventObject

*/

public class DoorEvent extends EventObject { private static final long serialVersionUID = 6496098798146410884L; private String doorState = "";// 表示门的状态,有“开”和“关”两种 

(2)定义新的事件监听接口,该接口继承自EventListener;该接口包含对doorEvent事件的处理程序:

/**

* 定义监听接口,负责监听DoorEvent事件

*/

public interface DoorListener extends EventListener { 
public void doorEvent(DoorEvent event); 

通过上面的接口我们再定义事件监听类,这些类具体实现了监听功能和事件处理功能。

/**

* 该类为 门1监听接口的实现,做具体的开门,关门动作

*/

public class DoorListener1 implements DoorListener { 

/**

* 该类为 门2监听接口的实现,做具体的开门,关门,以及开灯,关灯动作

*/

public class DoorListener2 implements DoorListener { 

(3)通过DoorManager.java创造一个事件源类,它用一个Collection listeners对象来存储所有的事件监听器对象,存储方式是通过addDoorListener(..)这样的方法。notifyListeners(..)是触发事件的方法,用来通知系统:事件发生了,你调用相应的处理函数吧。

/**

* 事件源对象,在这里你可以把它想象成一个控制开门关门的遥控器,

* (如果是在 swing 中,就类似一个button)

*/

public class DoorManager { private Collection listeners; /** 

(4)好了,最后写一个测试程序测试一下我们自定义的事件吧,这段程序应该不难理解吧:)

/**

* 主程序,就想象成要开门的哪个人

*/

public class DoorMain { public static void main(String[] args) { 

运行DoorMain

门1打开

门2打开,同时打开走廊的灯

我已经进来了

门1关闭

门2关闭,同时关闭走廊的灯

1、Java事件介绍

1.1什么是事件

首先我们来回答”什么是事件”这一基本问题。其实事件本身就是一个抽象的概念,他是表现另一对象状态变化的对象。在面向对象的程序设计中,事件消息是对象间通信的基本方式。在图形用户界面程序中, GUI 组件对象根据用户的交互产生各种类型的事件消息,这些事件消息由应用程序的事件处理代码捕获,在进行相应的处理后驱动消息响应对象做出反应。我们在GUI上进行叫化操作的时候,在点击某个可响应的对象时如,按钮,菜单,我们都会期待某个事件的发生。其实围绕GUI的所有活动都会发生事件,但Java事件处理机制却可以让您挑选出您需要处理的事件。事件在Java中和其他对象基本是一样的,但有一点不同的是,事件是由系统自动生成自动传递到适当的事件处理程序。

1.2Java事件处理的演变

当java的开发者开始解决用java创建应用程序这一问题时,他们就认识到java事件模型的必要性。下面对java事件处理的发展做简要的概括。

在JDK1.0的版本采用用的事件模型,提供了基本的事件处理功能。这是一种包容模型,所有事件都封装在单一的类Event中,所有事件对象都由单一的方法handleEvent来处理,这些定义都在 Component 类中。为此,只有Component类的子类才能充当事件处理程序,事件处理传递到组件层次结构,如果目标组件不能完全处理事件,事件被传递到目标组件的容器。

JDK1.1是编程界的一次革命,修正了前面版本的一些缺陷,同时增加了一些重要的新功能如,RMI、JNI、JDBC、 JavaBean 。在事件模型上基本框架完全重写,并从Java1.0模型迁移到委托事件模型,在委托模型中事件源生成事件,然后事件处理委托给另一段代码。

从JDK1.2开始,引入了Swing包事件处理模型功能更强大,更加可定制GUI组件与他们相关联的支持类。在后面的版本基本保持了整个事件模型,但加入了一些附加事件类和接口。在1.3版本开始引入Rebot类,它能模拟鼠标和键盘事件,并用于自动化测试、自动运行演示、以及其他要求鼠标和键盘控制的应用程序。

我们把JDK1.0事件处理模型成为java 1.0事件模型,而从jdk1.1后的版本事件处理 模型称为Java 2事件处理模型。

回页首

2、Java 2事件处理模型

在Java1.0事件处理模型中事件处理是以如下方法执行的。deliverEvent()用于决定事件的目标,目标是处理事件的组件或容器,此过程开始于GUI层的最外部而向内运作。当按一个button时,如果检测到是该按钮激发的事件,该按钮会访问它的deliverEvent()方法,这一操作由系统完成。一旦识别目标组件,正确事件类型发往组件的postEvent()方法,该方法依次把事件送到handleEvent()方法并且等待方法的返回值。”true”表明事件完全处理,”false”将使postEvent()方法联系目标容器,希望完成事件处理。

下面给一个实例:

import java.applet.*; 

在Java2处理事件时,没有采用dispatchEvent()-postEvent()-handleEvent()方式,采用了监听器类,每个事件类都有相关联的监听器接口。事件从事件源到监听者的传递是通过对目标监听者对象的Java方法调用进行的。

对每个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中,这个接口要继承java.util.EventListener。 实现了事件监听者接口中一些或全部方法的类就是事件监听者。 伴随着事件的发生,相应的状态通常都封装在事件状态对象中,该对象必须继承自java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。 发出某种特定事件的事件源的标识是:遵从规定的设计格式为事件监听者定义注册方法,并接受对指定事件监听者接口实例的引用。 有时,事件监听者不能直接实现事件监听者接口,或者还有其它的额外动作时,就要在一个源与其它一个或多个监听者之间插入一个事件适配器类的实例,来建立它们之间的联系。

我们来看下面一个简单的实例:

import javax.swing.*; 

回页首

3、事件捕获与回放

3.1 Java事件生命周期

Java事件和万事一样有其生命周期,会出生也会消亡。下图3.1给出了Java事件生命周期的示意图,

事件最初由事件源产生,事件源可以是GUI组件Java Bean或由生成事件能力的对象,在GUI组件情况下,事件源或者是组件的同位体(对于Abstract Window Toolkit[ awt ]GUI组件来说)或组件本身(对于Swing组件来说)。事件生成后放在系统事件队列内部。现在事件处于事件分发线程的控制下。事件在队列中等待处理,然后事件从事件队列中选出,送到dispatchEvent()方法,dispatchEvent()方法调用processEvent()方法并将事件的一个引用传递给processEvent()方法。此刻,系统会查看是否有送出事件的位置,如果没有这种事件类型相应的已经注册的监听器,或者如果没有任何组件受到激活来接收事件类型,事件就被抛弃。当然上图显示的是AWTEvent类的子类的生命周期。dispatchEvent()方法和processEvent()方法把AWTEvent作为一个参数。但对,javax.swing.event并不是AWTEvent子类,而是从EventObject直接继承过来,生成这些事件的对象也会定义fireEvent()方法,此方法将事件送到包含在对象监听器列表内的那种类型的任何监听器。

3.2 Java事件捕获

从上面的分析我们知道,任何事件产生到dispatchEvent()方法分发方法前,所有的事件都是存放在系统事件的队列中,而且所有的事件都由dispatchEvent()方法来分派。所以只要能重载dispatchEvent()方法就可以获取系统的所有事件,包括用户输入事件。一般来说,系统事件队列的操作对用户来说是可以控制。它在后台自动完成所要完成的事情,使用EventQueue类可以查看甚至操纵系统事件队列。

Java提供了EventQueue类来访问甚至操纵系统事件队列。EventQueue类中封装了对系统事件队列的各种操作,除dispatchEvent()方法外,其中最关键的是提供了push()方法,允许用特定的EventQueue来代替当前的EventQueue。只要从EventQueue类中派生一个新类,然后通过push()方法用派生类来代替当前的EventQueue类即可。这样,所有的系统事件都会转发到派生EventQueue类。然后,再在派生类中重载dispatchEvent()方法就可以截获所有的系统事件,包括用户输入事件。下面一段代码给出一个操纵EventQueue的实例:

import java.awt.*; 

运行结果如下图所示:

在文本域中首先出现的是”event is :test”,这是因为首先得到处理的是EventQueue对象发送到系统事件队列上的ActionEvent。

下面的代码简单说明了如何捕获事件:

import java.awt.EventQueue; 

这个程序可以打印出当前应用的所有的事件,可以将这些事件中选出你需要的事件保存当然你还需要解析该控件的特征。在上面加黑部分的代码,打印事件源控件的名称。

除此之外,还可以通过实现java.awt.event. AWTEventListener接口实现对事件的捕获。这个侦听器接口可以接收Component or MenuComponent 以及它们的派生类在整个系统范围内所分发的事件,AWTEventListeners只是被动的监控这些事件。如果要监控系统事件,除了要实现接口,还要用Toolkit的addAWTEventListener方法注册这个侦听器。

下面我们来看一个实例:

import java.awt.AWTEvent; 

3.3 Java事件回放

事件的回放其实比较简单了,比如我们现在记录的是frame1下的jButton1点击事件回放。看下面一段简单的程序,只要点一下jButton1,就在控制台打印一次”click me”的字符串。

import java.awt.*; 

下面是回放的程序,在下面的程序中用到了java.awt.Robot类,这个类通常用来在自动化测试或程序演示中模拟系统事件,在某些需要控制鼠标或键盘的应用程序中这个类也是很有用,这个类主要的目的就是为方便的实现java的GUI自动化测试平台。在事件回放时,我们同样需要该类来模拟生成系统的事件,完成记录的操作的回放,在下面的代码中,给出了一个简单的例子。

import java.awt.*; 

该程序运行完,你会发现在控制台同样打印出了:

“click me”的字符串说明事件被正确回放了。

当然还可以通过直接操纵系统事件队列实现输入事件的回放。先通过记录下的窗口/组件名获得对应窗口引用,然后重构鼠标/键盘事件,最后将重构的事件直接放入系统事件队列,由分派线程执行后续的事件分派工作。还需要解决关键问题如何能根据窗口名称获得其引用。这里还是可以通过系统事件队列来实现的,因为Java程序在新建/删除一个容器时都会向系统事件队列发出一个 Container event事件,其中包含了对该容器的引用。所以,事件回放器在载入被测测试程序后便监视系统队列,截获所有的Containerevent事件。如果新建容器,便获得新建Container的引用。因为所有的Container都实现了getComponets(),可以返回所有该容器所包含的组件或容器,只需要保存到一个HashMap结构中,需要时检索出来就可以了。该过程所用到的知识,其实在上面都有提到而且在实际引用中,既然Robot已经帮我们完成许多事情,也没有必要自己再去重构一个鼠标或键盘事件了,不过有兴趣的朋友也可以去试试。

文章来源:智云一二三科技

文章标题:Java编程事件处理机制分析

文章地址:https://www.zhihuclub.com/200016.shtml

关于作者: 智云科技

热门文章

网站地图