本文主要內容:事件處理的基礎概念,基本流程,還有一個簡單的按鈕事件例子(《Core Java》書中例子)。
1.事件處理基礎知識
JDK 1.1開始,Java的事件處理采用事件委托(代理)模型(event delegation)。
在這個模型中,比較重要的幾個概念如下:
(也可以看完第二部分的事件處理過程之后再來看這些概念,或許思路明朗一些)。
1.事件源(event source)
事件源是一個能夠注冊監聽器對象並發送事件對象的對象。例如按鈕或者滾動條就是事件源。
2.事件,事件類型和事件對象
事件一般是用戶在界面上的一個操作,當一個事件發生時,該事件用一個事件對象來表示,事件對象有對應的事件類。
不同的事件類描述不同類型的用戶動作,不同的事件源可以產生不同類別的事件。例如,按鈕可以發送ActionEvent對象,而窗口可以發送WindowEvent對象。
在Java中,所有的事件對象都最終派生於java.util.EventObject類。
3.事件監聽器(event listener)
監聽器對象是一個實現了特定監聽器接口(listener interface)的類的實例。
事件監聽器類(監聽器對象所屬的類)必須實現事件監聽器接口或繼承事件監聽器適配器類。
事件監聽器接口定義了處理事件必須實現的方法。
事件監聽器適配器類是對事件監聽器接口的簡單實現。目的是為了減少編程的工作量。
處理事件的方法被稱為事件處理器,即事件監聽器接口定義,並在事件監聽器類中實現的方法。
4.注冊事件監聽器
為了能夠讓事件監聽器檢查某個組件(事件源)是否發生了某些事件,並且在發生時激活事件處理器進行相應的處理,必須在事件源上注冊事件監聽器。
這是通過使用事件源組件的以下方法來完成的:
addXxxListener(事件監聽器對象)
Xxx對應相應的事件類。
5.再論事件和監聽器
每一類事件有一個相應的事件監聽器接口,該接口定義了接收和處理事件的抽象方法。實現該接口的類,就是監聽器類。其對象可作為監聽器對象向相應的組件注冊。
事件的類名通常為:XxxEvent
對應的事件監聽器接口名通常為:XxxListener
一個監聽器接口定義了一種以上的抽象事件處理方法(事件處理器)。
事件監聽器類實現事件監聽器接口,其類名可以由我們自己取。事件監聽器類需要我們自己編寫。
2.事件處理過程
在這個event delegation模型中,事件源產生事件對象,然后將其發送給所有注冊的的事件監聽器對象,監聽器對象利用事件對象中的信息決定如何對事件做出響應。
從網上找的ppt中的一個圖:
3.實例:處理按鈕點擊事件
為了加深理解,以一個簡單的例子來說明(《Core Java》書中例子)。
這個例子中:在一個面板中放置三個按鈕,添加三個監聽器對象用來作為按鈕的動作監聽器。
在這個情況下,只要用戶點擊面板上的任何一個按鈕,相關的監聽器對象就會接收到一個ActionEvent對象,它表示有個按鈕被點擊了。在示例程序中,監聽器對象將改變面板的背景顏色。
具體流程如下:
1.創建按鈕JButton,將按鈕添加到面板中(在面板中調用add方法);
2.需要一個實現了ActionListerner接口的類(事件監聽器類),它應該包含一個actionPerformed方法,其簽名為:
public void actionPerformed(ActionEvent event);
當按鈕被點擊時,我們希望將面板的背景顏色設置為指定的顏色。該顏色存儲在監聽器類中。
3.為每種顏色構造一個監聽器對象,將這些對象設置為按鈕監聽器,即,調用按鈕的addActionListener方法注冊監聽器。
代碼如下:

/** @version 1.32 2004-05-04 @author Cay Horstmann */ import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ButtonTest { public static void main(String[] args) { ButtonFrame frame = new ButtonFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } /** A frame with a button panel */ class ButtonFrame extends JFrame { public ButtonFrame() { setTitle("ButtonTest"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add panel to frame ButtonPanel panel = new ButtonPanel(); add(panel); } public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; } /** A panel with three buttons. */ class ButtonPanel extends JPanel { public ButtonPanel() { // create buttons JButton yellowButton = new JButton("Yellow"); JButton blueButton = new JButton("Blue"); JButton redButton = new JButton("Red"); // add buttons to panel add(yellowButton); add(blueButton); add(redButton); // create button actions ColorAction yellowAction = new ColorAction(Color.YELLOW); ColorAction blueAction = new ColorAction(Color.BLUE); ColorAction redAction = new ColorAction(Color.RED); // associate actions with buttons yellowButton.addActionListener(yellowAction); blueButton.addActionListener(blueAction); redButton.addActionListener(redAction); } /** An action listener that sets the panel's background color. */ private class ColorAction implements ActionListener { public ColorAction(Color c) { backgroundColor = c; } public void actionPerformed(ActionEvent event) { setBackground(backgroundColor); } private Color backgroundColor; } }
例如,如果有一個用戶在標有“Yellow”的按鈕上點擊了一下,那么yellowAction對象的actionPerformed方法就會被調用。這個對象的backgroudColor實例域設置為Color.YELLOW,然后就將面板的顏色設置為黃色了。
有一個需要考慮的問題,是ColorAction對象(監聽器對象)沒有權限訪問panel變量。可以采用兩種方式解決這個問題:
1.將面板存儲在ColorAction對象中,並在ColorAction構造器中設置它;
2.將ColorAction作為ButtonPanel類的內部類。這樣一來,ColorAction就自動地擁有訪問外部類的權限了。
這里使用的就是第二種方法,ColorAction類中調用過了外部類ButtonPanel中的setBackground方法。這種情形十分常見,事件監聽器對象通常需要執行一些對其他對象可能產生影響的操作,可以策略性地將監聽器類放置在需要修改狀態的那個類中。