在新的事件模型的組件可以開始一個事件。每種類型的事件被一個個別的類所描繪。當事件開始後,它受理一個或更多事件指明“接收器”。因此,事件源和處理事件的地址可以被分離。
每個事件接收器都是執行特定的接收器類型接口的類對象。因此作為一個程序開發者,我們所要做的是創建接收器對象並且在被激活事件的組件中進行注冊。event-firing組件調用一個addXXXListener()方法來完成注冊,以描述XXX事件類型接受。我們可以容易地了解到以addListened名的方法通知我們任何的事件類型都可以被處理,如果我們試圖接收事件我們會發現編譯時我們的錯誤。Java Beans同樣使用這種addListener名的方法去判斷那一個程序可以運行。
我們所有的事件邏輯將裝入到一個接收器類中。當我們創建一個接收器類時唯一的一點限制是必須執行專用的接口。我們可以創建一個全局接收器類,這種情況在內部類中有助於被很好地使用,不僅僅是因為它們提供了一個理論上的接收器類組到它們服務的UI或業務邏輯類中,但因為(正像我們將會在本章後面看到的)事實是一個內部類維持一個句柄到它的父對象,提供了一個很好的通過類和子系統邊界的調用方法。
一個簡單的例子將使這一切變得清晰明確。同時思考本章前部Button2.java例子與這個例子的差異。
//: Button2New.java // Capturing button presses import java.awt.*; import java.awt.event.*; // Must add this import java.applet.*; public class Button2New extends Applet { Button b1 = new Button("Button 1"), b2 = new Button("Button 2"); public void init() { b1.addActionListener(new B1()); b2.addActionListener(new B2()); add(b1); add(b2); } class B1 implements ActionListener { public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 1"); } } class B2 implements ActionListener { public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 2"); } } /* The old way: public boolean action(Event evt, Object arg) { if(evt.target.equals(b1)) getAppletContext().showStatus("Button 1"); else if(evt.target.equals(b2)) getAppletContext().showStatus("Button 2"); // Let the base class handle it: else return super.action(evt, arg); return true; // We've handled it here } */ } ///:~
我們可比較兩種方法,老的代碼在左面作為注解。在init()方法裡,只有一個改變就是增加了下面的兩行:
b1.addActionListener(new B1());
b2.addActionListener(new B2());
按鈕按下時,addActionListener()通知按鈕對象被激活。B1和B2類都是執行接口ActionListener的內部類。這個接口包括一個單一的方法actionPerformed()(這意味著當事件激活時,這個動作將被執行)。注意actionPreformed()方法不是一個普通事件,說得更恰當些是一個特殊類型的事件,ActionEvent。如果我們想提取特殊ActionEvent的信息,因此我們不需要故意去測試和下溯造型自變量。
對編程者來說一個最好的事便是actionPerformed()十分的簡單易用。它是一個可以調用的方法。同老的action()方法比較,老的方法我們必須指出發生了什麼和適當的動作,同樣,我們會擔心調用基礎類action()的版本並且返回一個值去指明是否被處理。在新的事件模型中,我們知道所有事件測試推理自動進行,因此我們不必指出發生了什麼;我們剛剛表示發生了什麼,它就自動地完成了。如果我們還沒有提出用新的方法覆蓋老的方法,我們會很快提出。