软件系统中的事件处理允许两个或者多个对象根据它们的状态的变化进行通信和协调,在常见的事件处理模型中,对象通常被划分为三种:事件对象,事件制造者对象和事件接收者对象。一般而言,某一个对象是事件的制造者,蓁对象是事件的接收者,而事件对象本身封装了有关事件的信息,当事件制造者的内部状态发生变化时,会根据需要创建一个代表其状态变化的事件对象,并将它传给所有登记过的事件接收者对象.
java1.0的事件处理机制是建立在责任链模式的基础上的,这样的事件处理机制不能满足大型应用系统的需要,在java1.1版本里,java事件处理机制有了一个较大的变化,新的事件处理机制是建立在观察者模式基础之上的,以事件的委派为特征的委派事件模型(Delegation Event Model,DEM)。
一:DEM的结构
(A)一个类要成为事件源并不需要实现任何接口或者继承任何类,但是一个事件源需要保持一个事件监听器的列表,调用addXXXListener方法增加一个监听器,调用removeXXXListener方法删除一个监听器。
(B)事件对象,在DEM中,每种事件都有一个事件对象与之对应,而所有的AWT中的事件对象都是从java.util.EventObject继承而来的,每一种具体的事件对象都有一些额外的功能。 Swing构件引进了更多的事件类,这些事件类不是从AWTEvent衍生来的,而是直接从EventObject衍生出来的。事件对象封装了事件的源对象与事件监听器对象所需要的事件信息。有一些事件类比如PaintEvent是不会被传递给监听器的,因此对java程序员来说并没有什么用处.
(C)事件监听器对象,事件舰艇器对象是当事件发生时被调用的对象,一个对象要成为事件监听器对象必须要实现事件监听器接口,AWT库中所有的事件监听器接口都是java .util.EventListener接口的子接口。
(D)事件监听适配器:这些适配器类为它们所实现的接口提供空的实现,这样一来,一个需要处理某个事件的应用类只需要继承相应的事件适配器类,并置换掉感兴趣的方法即可,这些事件监听适配器都是缺省模式的应用.
(E)语义事件与底层事件:AWT区分了底层事件(Low-level-Event)和语义事件(Semantic Event)。一个语义事件表达了用户所做的事情,比如使用鼠标单击一个按键就是一个语义事件,相应的ActionEvent就是一个语义事件。一个底层事件则是组成各种语义事件的单纯事件,比如鼠标单击事件是由一个鼠标按下事件和一个鼠标释放事件组成,类似地调整滚动条是一个语义事件,而拖曳鼠标则是一个底层事件.
AWT中最重要的四个语义事件:
(1)ActionEvent :单击按键,选择菜单项,选择列表项,在文字框中输入文字等
(2)AdjustmentEvent :调整滚动条
(3)ItemEvent :用户在一组选择框中选择一个或者在列表中选择一项
(4)TextEvent :文字框的内容有变化
AWT中六个底层事件类:
ComponentEvent :构件大小改变,位置变化,被隐藏,被显现
KeyEvent:一个键被按下或者施放
MouseEvent:鼠标按下,释放,移动或者拖曳
FocusEvnet :一个构件得到或者失去聚焦
WindowEvent:视窗被激活,释放,最小化,关闭等。
ContainerEvent:一个构件被增加到容器中或者从容器中删除.
二:一个例子
现在请看一个例子,显示一个空视窗,接收鼠标单击事件。为了更好的说明AWT事件机制与观察者模式的关系,下面给出了四种不同的设计:
(A)第一种设计
在这个设计里,事件主题(事件源)和事件监听器是两个分开的对象,分别是ConcreteSubject和ConcreteListener,前者是可见的Frame对象,后者是在后台的事件监听对象.
从下面的代码可以看出,Frame实际上扮演了抽象主题角色,而ConcreteSubject则是具体主题角色,MouseListener接口扮演抽象观察者角色,而ConcreteListener则是具体观察者角色,从主题角色传递给抽象观察者的事件对象就是MouseEvent对象.,下面请看源码:
package cai.milenfan.basic.test;
import java.awt.Frame;
import java.awt.event.MouseListener;
public class ConcreteSubject extends Frame{
private static MouseListener m;
public ConcreteSubject(){
}
public static void main(String[] argv){
ConcreteSubject s = new ConcreteSubject();
m = new ConcreteListener();
s.setBounds(100, 100, 100 , 100);
s.addMouseListener(m);
s.show();
}
}
package cai.milenfan.basic.test;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ConcreteListener implements MouseListener{
ConcreteListener() {
}
public void mouseClicked(MouseEvent e) {
System.out.println(e.getWhen());
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
第二种方案:这种方案用了事件适配器类MouseAdapter,它实现了MouseListener接口,为所有的方法都提供了空实现,这样ConcreteListener类就只需要继承MouseAdapter并且置换mouseClicked方法就可以了。代码略.
第三种方案:这种方案的主题和监听器是合二为一的:这个类继承了Frame类,并且实现了MouseListener接口:
package cai.milenfan.basic.test;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ConcreteSubject extends Frame implements MouseListener{
private static MouseListener m;
public ConcreteSubject(){
}
public void mouseClicked(MouseEvent e){
System.out.println(e.getWhen());
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public static void main(String[] argv){
ConcreteSubject s = new ConcreteSubject();
s.setBounds(100, 100, 100 , 100);
s.addMouseListener(s);
s.show();
}
}
第四种设计是Java设计师的常用设计,在这个设计中,视窗是ConcreteSubject类,而事件监听器则由一个内部无名类实现:
package cai.milenfan.basic.test;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ConcreteSubject extends Frame{
public ConcreteSubject(){
}
public static void main(String[] argv){
ConcreteSubject s = new ConcreteSubject();
s.setBounds(100, 100, 100 , 100);
s.addMouseListener( new MouseListener() {
public void mouseClicked(MouseEvent e) {
System.out.println(e.getWhen());
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
}
);
s.show();
}
private MouseListener lnkMouseListener;
}