Java 事件監聽原理及Demo實現

簡介

Java的事件監聽是Java事件機制的實現,以Java Swing的事件機制爲例,分析一下事件監聽的各個組成部分以及功能:


Java事件機制的三個基本組成成分

1.事件對象

通常繼承自java.util.EventObject的對象,一般可以用來判斷事件類型的作用

2.事件源

觸發事件的源頭,在GUI和Swing編程中,如Button按鈕等對象就是一個事件源

3.事件監聽器

負責監聽事件源發出的事件並作出響應動作的對象,通常實現java.util.EventListener接口

事件的一般流程

1.事件源註冊監聽器

2.事件發生,事件源向監聽器發送事件對象

3.監聽器對象響應事件


實現

下面用Demo來介紹事件機制的實現原理

1.事件對象類

import java.util.EventObject;

/**
 * Created by Xuyh at 2016/11/30 下午 04:00.
 *
 * <pre>
 *     自己理解事件對象的作用:
 *     (1)事件對象儲存了事件源對象,
 *     當事件監聽器方法進行處理程序的時候,
 *     如果需要改變事件源的屬性值等等操作時候,
 *     就可以通過事件對象獲取到事件源對象,
 *     從而對事件事件源的屬性進行修改或者調用事件源的方法。
 *     (2)繼承了java.util.EventObject之後的自定義事件對象,
 *     可以添加其他屬性,比如說事件類型等等,
 *     添加一些必要的業務屬性等。
 *
 * </pre>
 */
public class JohnsonEventObject extends EventObject {
	public static int EVENT_TYPE_ONE = 1;
	public static int EVENT_TYPE_TWO = 2;
	public static int EVENT_TYPE_THREE = 3;
	private int eventType;

	/**
	 * source是事件源
	 *
	 * @param source
	 */
	public JohnsonEventObject(Object source) {
		super(source);
	}

	public JohnsonEventObject(Object source, int eventType) {
		super(source);
		this.eventType = eventType;
	}

	@Override
	public Object getSource() {
		return super.getSource();
	}

	@Override
	public String toString() {
		return super.toString();
	}

	public int getEventType() {
		return eventType;
	}

	public void setEventType(int eventType) {
		this.eventType = eventType;
	}
}

在該事件對象類中,除了默認繼承自java.util.EventObject的source(即事件源對象屬性)之外,另外添加了一個eventType(事件類型屬性),用來代表事件的類型。

當事件發生後,事件監聽器的響應方法會接受到事件對象(作爲方法參數被傳遞),事件對象中的事件源屬性可以提供數據源對象供響應方法調用,從而改變事件源的屬性等。


2.事件源類

import java.util.HashSet;
import java.util.Set;

/**
 * Created by Xuyh at 2016/11/30 下午 04:00.
 *
 * <pre>
 *     事件源是事件發生的地方,
 *     是事件觸發的源頭,
 *     事件監聽器註冊的地方。
 * </pre>
 */
public class JohnsonEventSource {
	/**
	 * 事件監聽器的集合
	 * 
	 * <pre>
	 *     事件源中存儲一個監聽器集合,
	 *     當事件發生之後,事件源會依次調用
	 *     每個監聽器的響應方法。
	 * </pre>
	 */
	private Set<JohnsonEventListener> eventListeners = new HashSet<JohnsonEventListener>();

	/**
	 * 註冊監聽器
	 * 
	 * <pre>
	 *     理解:
	 *     添加監聽器
	 * </pre>
	 *
	 * @param eventListener
	 */
	public void addEventListener(JohnsonEventListener eventListener) {
		if (eventListener != null) {
			eventListeners.add(eventListener);
		}
	}

	/**
	 * 註銷監聽器
	 * 
	 * <pre>
	 *     理解:
	 *     把這個監聽器去掉
	 * </pre>
	 *
	 * @param eventListener
	 * @return
	 */
	public boolean removeEventListener(JohnsonEventListener eventListener) {
		return eventListeners.remove(eventListener);
	}

	/**
	 * 發生事件1
	 * 
	 * <pre>
	 * 發生事件方法需要外部調用
	 * </pre>
	 */
	public void event1() {
		JohnsonEventObject object = new JohnsonEventObject(this, JohnsonEventObject.EVENT_TYPE_ONE);
		doOnAction(object);
	}

	/**
	 * 發生事件2
	 * 
	 * <pre>
	 * 發生事件方法需要外部調用
	 * </pre>
	 */
	public void event2() {
		JohnsonEventObject object = new JohnsonEventObject(this, JohnsonEventObject.EVENT_TYPE_TWO);
		doOnAction(object);
	}

	/**
	 * 發生事件3
	 * 
	 * <pre>
	 * 發生事件方法需要外部調用
	 * </pre>
	 */
	public void event3() {
		JohnsonEventObject object = new JohnsonEventObject(this, JohnsonEventObject.EVENT_TYPE_THREE);
		doOnAction(object);
	}

	/**
	 * 遍歷監聽器執行響應方法
	 * 
	 * @param eventObject
	 */
	private void doOnAction(JohnsonEventObject eventObject) {
		for (JohnsonEventListener listener : eventListeners) {
			listener.onAction(eventObject);
		}
	}

	/**
	 * <pre>
	 * 定義一個事件源方法,
	 * 給事件監聽器調用,
	 * 用來體現事件對象保存事件源的作用。
	 * </pre>
	 * 
	 * @param message
	 */
	public void sourceFunction(String message) {
		System.out.println(message);
	}
}
事件源是事件觸發的地方,其中有一個事件監聽器集合,通過addEventListener方法可以添加事件監聽器到監聽器集合中,也就是經常說的“註冊事件監聽器”。

其中的doOnAction方法是必不可少的一個操作,即在事件發生之後遍歷監聽器集合,執行監聽器定義的動作響應方法。

event1,event2,event3是定義的三個事件方法,模擬事件的發生,發生事件之後程序需要實例化事件對象(事件對象儲存了事件源即本對象的引用),並將其作爲參數依次調用每個監聽器的動作響應方法,即上面的步驟。


3.事件監聽器類

import java.util.EventListener;

/**
 * Created by Xuyh at 2016/11/30 下午 04:00.
 *
 * <pre>
 *     事件監聽器定義了一個接口,
 *     用來規範事件發生之後事件源調用的處理方法
 * </pre>
 */
public interface JohnsonEventListener extends EventListener {
	/**
	 * 事件產生需要調用的方法
	 */
	public void onAction(JohnsonEventObject eventObject);
}
事件監聽器是一個接口,裏面定義了一個固定名字的響應方法,用來提供給事件源調用。

註冊事件監聽器就是實現監聽器接口的響應方法並添加到事件源的監聽器集合中。


其中,事件對象繼承自java.util.EventObject ,源碼如下

package java.util;

/**
 * <p>
 * The root class from which all event state objects shall be derived.
 * <p>
 * All Events are constructed with a reference to the object, the "source",
 * that is logically deemed to be the object upon which the Event in question
 * initially occurred upon.
 *
 * @since JDK1.1
 */

public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /**
     * The object on which the Event initially occurred.
     */
    protected transient Object  source;

    /**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    /**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource() {
        return source;
    }

    /**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

事件監聽類實現java.util.EventListener 接口,源碼如下:

package java.util;

/**
 * A tagging interface that all event listener interfaces must extend.
 * @since JDK1.1
 */
public interface EventListener {
}


使用

定義好了事件監聽Demo之後就可以測試使用了,下面根據這個Demo來實現幾種事件監聽的實現方式:

1.自身類作爲事件監聽器 :

import event.JohnsonEventListener;
import event.JohnsonEventObject;
import event.JohnsonEventSource;

/**
 * 自身類作爲事件監聽器
 * 
 * @Author Xuyh created at 2016年12月11日 下午5:57:46
 *
 */
public class TestMain implements JohnsonEventListener {

	public void onAction(JohnsonEventObject eventObject) {
		JohnsonEventSource source = (JohnsonEventSource) eventObject.getSource();
		source.sourceFunction("事件監聽器  監聽到事件--事件類型: " + String.valueOf(eventObject.getEventType()));
	}

	public static void main(String[] args) {
		JohnsonEventSource source = new JohnsonEventSource();
		source.addEventListener(new TestMain());
		source.event1();
		source.event2();
		source.event3();
	}

}

2.外部類作爲事件監聽器 :

監聽器:

package xuyihao;

import event.JohnsonEventListener;
import event.JohnsonEventObject;
import event.JohnsonEventSource;

/**
 * 外部類作爲事件監聽器的外部類
 * 
 * @Author Xuyh created at 2016年12月11日 下午6:02:46
 *
 */
public class OuterListerner implements JohnsonEventListener {

	public void onAction(JohnsonEventObject eventObject) {
		JohnsonEventSource source = (JohnsonEventSource) eventObject.getSource();
		source.sourceFunction("事件監聽器  監聽到事件--事件類型: " + String.valueOf(eventObject.getEventType()));
	}
}


/**
 * 外部類作爲事件監聽器的外部類
 * 
 * @Author Xuyh created at 2016年12月11日 下午6:02:46
 *
 */
public class JohnsonMain {
	public static void main(String args[]) {
		exentTest();
	}

	/**
	 * 外部類作爲事件監聽器
	 */
	public static void exentTest() {
		JohnsonEventSource source = new JohnsonEventSource();
		source.addEventListener(new OuterListerner());
		source.event1();
		source.event2();
		source.event3();
	}
}

/**
 * 
 * 
 * @Author Xuyh created at 2016年12月11日 下午6:02:46
 *
 */
public class JohnsonMain {
	public static void main(String args[]) {
		exentTest();
	}

	/**
	 * 外部類作爲事件監聽器
	 */
	public static void exentTest() {
		JohnsonEventSource source = new JohnsonEventSource();
		source.addEventListener(new OuterListerner());
		source.event1();
		source.event2();
		source.event3();
	}
}


3.匿名內部類作爲事件監聽器 :

import event.JohnsonEventListener;
import event.JohnsonEventObject;
import event.JohnsonEventSource;

public class JohnsonMain {
	public static void main(String args[]) {
		eventTest();
	}
		

	/**
	 * 匿名方式實現監聽
	 */
	public static void eventTest() {
		System.out.println("匿名方式實現監聽");
		// 定義事件源
		JohnsonEventSource source = new JohnsonEventSource();
		// 事件源綁定事件監聽1,這裏使用匿名方式實現監聽器
		source.addEventListener(new JohnsonEventListener() {
			public void onAction(JohnsonEventObject eventObject) {
				JohnsonEventSource source1 = (JohnsonEventSource) eventObject.getSource();
				source1.sourceFunction("事件監聽器 1 監聽到事件--事件類型: " + String.valueOf(eventObject.getEventType()));
				// 這裏也可以直接使用外部的source對象,本質上是一個對象
			}
		});
		// 事件源綁定事件監聽2
		source.addEventListener(new JohnsonEventListener() {
			public void onAction(JohnsonEventObject eventObject) {
				JohnsonEventSource source2 = (JohnsonEventSource) eventObject.getSource();
				source2.sourceFunction("事件監聽器 2 監聽到事件--事件類型: " + String.valueOf(eventObject.getEventType()));
			}
		});
		// 啓動事件
		source.event1();
		source.event2();
		source.event3();
	}
}

4.內部類作爲事件監聽器:

import event.JohnsonEventListener;
import event.JohnsonEventObject;
import event.JohnsonEventSource;

/**
 * 內部類作爲事件監聽器
 *
 * Created by Xuyh at 2016/08/05 下午 03:26.
 */
public class JohnsonMain {
	public static void main(String args[]) {
		eventTest();
	}

	/**
	 * 定義監聽器類實現接口方式
	 */
	public static void eventTest() {
		System.out.println("定義監聽器類實現接口方式實現監聽");
		JohnsonEventSource source = new JohnsonEventSource();
		// 事件源綁定事件監聽1
		source.addEventListener(new ExampleListener(1));
		// 事件源綁定事件監聽2
		source.addEventListener(new ExampleListener(2));
		// 啓動事件
		source.event1();
		source.event2();
		source.event3();
	}

	public static class ExampleListener implements JohnsonEventListener {
		private int number;

		public ExampleListener(int number) {
			this.number = number;
		}

		public void onAction(JohnsonEventObject eventObject) {
			JohnsonEventSource source = (JohnsonEventSource) eventObject.getSource();
			source.sourceFunction("事件監聽器 " + number + " 監聽到事件--事件類型: " + String.valueOf(eventObject.getEventType()));
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章