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());
}
}