Java 1.1 引入的委派事件模型,讓元件可動態註冊/移除多個監聽器,不再像 1.0 版那般被迫在 handleEvent() 中硬編碼判斷邏輯。本文透過實例展示如何在執行期動態增減 ActionListener,實現更靈活的互動行為。
//: DynamicEvents.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class DynamicEvents extends Frame {
Vector<ActionListener> v = new Vector<>();
int i = 0;
Button b1 = new Button("Button 1"), b2 = new Button("Button 2");
public DynamicEvents() {
setLayout(new FlowLayout());
// 每個按鈕初始註冊兩個監聽器
b1.addActionListener(new B());
b1.addActionListener(new B1());
b2.addActionListener(new B());
b2.addActionListener(new B2());
add(b1); add(b2);
}
// 共用基礎監聽器
class B implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("A button was pressed");
}
}
// 計數監聽器
class CountListener implements ActionListener {
int index;
CountListener(int i) { index = i; }
public void actionPerformed(ActionEvent e) {
System.out.println("Counted Listener " + index);
}
}
// Button 1 被按:為 Button 2 新增一個計數監聽器
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Button 1 pressed");
ActionListener a = new CountListener(i++);
v.addElement(a);
b2.addActionListener(a);
}
}
// Button 2 被按:移除最後一個計數監聽器
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Button 2 pressed");
int end = v.size() - 1;
if (end >= 0) {
b2.removeActionListener((ActionListener)v.elementAt(end));
v.removeElementAt(end);
}
}
}
public static void main(String[] args) {
Frame f = new DynamicEvents();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
f.setSize(300, 200);
f.setVisible(true);
}
} ///:~
單一元件可註冊多個同類型監聽器(addActionListener 可重複呼叫)。事件觸發時,所有監聽器依註冊順序依序被通知。若元件設計為單播(如某些自訂元件),嘗試註冊第二個監聽器會拋出 TooManyListenersException。
addXXXListener(Listener l)removeXXXListener(Listener l),需持有監聽器參考才能精準移除。範例中使用 Vector 保存動態建立的 CountListener 參考,實現「疊加/移除」行為。
雖然實務上多依註冊順序觸發,但規範不保證呼叫順序。邏輯不應依賴監聽器執行順序。
Swing/JavaFX 繼承此模型。現代開發常搭配:
掌握動態事件綁定,能讓你的 UI 邏輯更模組化、更適應複雜互動需求。