Event Beginning
引自:http://blog.csdn.net/bear110/archive/2006/06/30/854507.aspx
如果你已经能够熟练使用jdk为我们提供的事件监听器,并且很熟悉MouseEvent, KeyEvent, WindowEvent等等这些jdk为我们准备好的事件,那么想必你对java的事件机制已经有所理解。但是也许你还是觉得虽然用起来没什么问题,但是原理还是有些糊涂,那么下面我们再进一步自己实现这些事件和监听器,我们把这个取名为自定义事件。
其实自定义事件在java中很有用处,我们有的时候想让自己的程序产生一个事件,但有不希望(或者不可能)用鼠标,键盘之类的输入设备进行操作,比如你写一个应用程序,在这个程序中一旦收到邮件就对邮件进行相关处理,对于“收到邮件”这个事件,jdk中就没有定义。对于这样的事件,以及对于这样的事件的监听器,我们只能自己动手完成了。
那么下面就以实例开始我们这个“创新”的过程:首先,我们要明确jdk中需要的资源:类EventObject作为父类用来生成我们自己的事件类,接口EventListener用来实现我们自己的监听器;剩下的事情就是如何注册这些事件以及测试他们了。
让我们一步一步实现它吧:
(1)通过DemoEvent.java文件创建DemoEvent类,这个类继承EventObject。这个类的构造函数的参数传递了产生这个事件的事件源(比如各种控件),方法getSource用来获得这个事件源的引用。
DemoEvent.java
package demo.listener;
import java.util.EventObject;
public class DemoEvent extends EventObject
{
Object obj;
public DemoEvent(Object source)
{
super(source);
obj = source;
}
public Object getSource()
{
return obj;
}
public void say()
{
System.out.println("This is say method...");
}
}
(2)定义新的事件监听接口,该接口继承自EventListener;该接口包含对DemeEvent事件的处理程序:
DemoListener.java
package demo.listener;
import java.util.EventListener;
public interface DemoListener extends EventListener
{
public void demoEvent(DemoEvent dm);
}
通过上面的接口我们再定义事件监听类,这些类具体实现了监听功能和事件处理功能。回想一下上文中那四种实现方式,我们这里不正是使用了其中的第三种——外部类写法的方式吗?
Listener1.java
package demo.listener;
public class Listener1 implements DemoListener
{
public void demoEvent(DemoEvent de)
{
System.out.println("Inside listener1...");
}
}
Listener2.java
package demo.listener;
public class Listener2 implements DemoListener
{
public void demoEvent(DemoEvent de)
{
System.out.println("Inside listener2...");
}
}
Listener3.java
package demo.listener;
public class Listener3 implements DemoListener
{
public void demoEvent(DemoEvent de)
{
System.out.println("Inside listener3...");
}
}
(3)通过DemeSource.java文件创造一个事件源类,它用一个java.utile.Vector对象来存储所有的事件监听器对象,存储方式是通过addListener(..)这样的方法。notifyDemeEvent(..)是触发事件的方法,用来通知系统:事件发生了,你调用相应的处理函数(回调函数)吧。
DemoSource.java
package demo.listener;
import java.util.*;
public class DemoSource
{
private Vector repository = new Vector();
DemoListener dl;
public DemoSource()
{
}
public void addDemoListener(DemoListener dl)
{
repository.addElement(dl);
}
public void notifyDemoEvent()
{
Enumeration enum = repository.elements();
while(enum.hasMoreElements())
{
dl = (DemoListener)enum.nextElement();
dl.demoEvent(new DemoEvent(this));
}
}
}
(4)好了,最后写一个测试程序测试一下我们自定义的事件吧,这段程序应该不难理解吧:)
TestDemo.java
package demo.listener;
public class TestDemo
{
DemoSource ds;
public TestDemo()
{
try{
ds = new DemoSource();
Listener1 l1 = new Listener1();
Listener2 l2 = new Listener2();
Listener3 l3 = new Listener3();
ds.addDemoListener(l1);
ds.addDemoListener(l2);
ds.addDemoListener(l3);
ds.notifyDemoEvent();
}catch(Exception ex)
{ex.printStackTrace();}
}
public static void main(String args[])
{
new TestDemo();
}
}
引自:http://blog.csdn.net/Arhero/archive/2004/11/23/192486.aspx
一、java事件处理机制
java中采取的是面向对象的机制。如在java中,要实现自定义事件处理,必须经过如下的步骤:
1 开发自定义事件类。
2 定义监听者接口。
3 定义事件激发者的接口。
public void add监听者(监听者);
public void remove监听者(监听者);
protected void process事件(事件);
4 实现事件激发者.
5 实现监听这接口。
java中的事件机制是很好理解的。当一个事件激发事,就调用process事件方法。这个事件方法会将所有的监听者一一执行它监听该事件的接口。(如果消息不消费,允许传递的话。)当然这也不是必须的,因为process方法是自己写的,可以自行决定它执行的动作。
实际上,java还有一种简单的事件处理机制。那就是目前不予推荐的继承模式。由于简单性,又不能不说这也可以是编程的一种选择。但是它在处理事件时,却只有一种选择,那就是扩展激发事件的构件并将事件处理代码嵌入到扩展部分。要做的步骤是:
1 覆盖事件处理函数。
如Applet中的public boolean mouseDown(Event evt, int x, int y).
如果要激发和处理自定义事件,如果比较多, 可以仿照awt的做法:
激发事件processEvent()--->定位--->process适当Event()--->将事件传递到事件处理函数
二、EventHandler
EventHandler 类为动态生成事件侦听器提供支持,这些侦听器的方法执行一条涉及传入事件对象和目标对象的简单语句。
EventHandler 类由交互工具(比如应用程序生成器)使用,这些工具允许开发人员在 bean 之间建立连接。通常是建立从用户界面 bean(事件 source)到应用程序逻辑 bean(target)的连接。大多数这类有效连接隔离了应用程序逻辑与用户界面。例如,用于从 JCheckBox 到接受 boolean 值的方法之间连接的 EventHandler 可以提取复选框的状态,并将其直接传递给该方法,从而使该方法与用户界面层隔离。
内部类是处理来自用户界面的事件的另一种更常见方法。EventHandler 类只处理可能使用内部类的事件的子集。不过,EventHandler 使用长期持久方案要比使用内部类更有效。同样,在同一接口被实现很多次的大型应用程序中,使用 EventHandler 可以减少应用程序的磁盘和内存占用。
使用 EventHandler 创建侦听器占用内存如此之少的原因是,EventHandler 所依赖的 Proxy 类共享了同一接口的实现。例如,如果使用 EventHandler 的 create 方法生成某个应用程序中的所有 ActionListener,则所有动作侦听器都将是单个类(由 Proxy 类创建)的实例。通常,基于 Proxy 类的侦听器要求为每个侦听器类型(接口)创建一个侦听器类,而使用内部类时要求为每个侦听器(实现接口的对象)创建一个类。
通常不需要直接处理 EventHandler 实例。相反,可使用 EventHandler 的 create 方法之一创建实现给定侦听器接口的对象。此侦听器对象在后台使用一个 EventHandler 对象来封装关于事件的信息、发生事件时接收消息的对象、要发送的消息(方法)和方法的任意参数。以下部分给出了如何使用 create 方法创建侦听器对象的示例。
使用 EventHandler 的示例:
EventHandler 最简单的使用方法是安装一个侦听器,不带参数地在目标对象上调用某个方法。在以下示例中,将创建一个在 javax.swing.JFrame 的实例上调用 toFront 方法的 ActionListener。
myButton.addActionListener(
(ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));
当按下 myButton 时,将执行 frame.toFront() 语句。通过定义 ActionListener 接口的新实现并将其实例添加到按钮中,用户可以获得同样的效果,且具有额外的编译时类型安全:
//Equivalent code using an inner class instead of EventHandler.
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.toFront();
}
});
EventHandler 的另一种最简单用法是从侦听器接口(通常是一个事件对象)中的方法的第一个参数中提取属性值,并用其设置目标对象中的属性值。在以下示例中,将创建一个 ActionListener,它将目标对象的 nextFocusableComponent 属性设置为事件的 "source" 属性的值。
EventHandler.create(ActionListener.class, target, "nextFocusableComponent", "source")
这将对应于以下内部类实现:
//Equivalent code using an inner class instead of EventHandler.
new ActionListener() {
public void actionPerformed(ActionEvent e) {
button.setNextFocusableComponent((Component)e.getSource());
}
}
EventHandler 最常见的用法可能是从事件对象的 source 中提取属性值,并将此值设置为目标对象的属性值。在以下示例中,将创建一个 ActionListener,它将目标对象的 "label" 属性设置为事件源的 "text" 属性的值("source" 属性的值)。
EventHandler.create(ActionListener.class, button, "label", "source.text")
这将对应于以下内部类实现:
//Equivalent code using an inner class instead of EventHandler.
new ActionListener {
public void actionPerformed(ActionEvent e) {
button.setLabel(((JTextField)e.getSource()).getText());
}
}
可以使用以 "." 字符分隔的任意数量的属性前缀来“限定”事件属性。采用出现在 "." 字符前面的“限定”名称作为将应用于事件对象的属性名称,最左边的最先应用。
例如,以下动作侦听器
EventHandler.create(ActionListener.class, target, "a", "b.c.d")
可以写成以下内部类(假定所有属性都有规范的 getter 方法并返回适当的类型):
//Equivalent code using an inner class instead of EventHandler.
new ActionListener {
public void actionPerformed(ActionEvent e) {
target.setA(e.getB().getC().isD());
}
}