深入JAVA事件触发

SWT中事件的触发借助于底层操作系统,因此首先贴出windows下的系统函数:
LRESULT CALLBACK WindowProc(
  _In_  HWND hwnd,
  _In_  UINT uMsg,
  _In_  WPARAM wParam,
  _In_  LPARAM lParam
);

当用户单击某个控件时首先由操作系统调用Display的windowProc方法

/*
*handle为系统事件的句柄140051169515536
*userata为事件类型(注意:这里事件指的是系统事件)
*/
long /*int*/ windowProc (long /*int*/ handle, long /*int*/ user_data) {
	Widget widget = getWidget (handle);//根据句柄获得相应的控件,本例子中为Button
	if (widget == null) return 0;
	return widget.windowProc (handle, user_data);//调用widget的windowProc函数,
	//该函数并没有被子类Button重写,因此Button继承了父类的函数
}

Widget的windowProc函数
//根据系统事件类型(user_data),调用相应的处理函数,这里为Button重写的gtk_clicked函数。
long /*int*/ windowProc (long /*int*/ handle, long /*int*/ user_data) {
	switch ((int)/*64*/user_data) {
		case ACTIVATE: return gtk_activate (handle);
		case CHANGED: return gtk_changed (handle);
		case CLICKED: return gtk_clicked (handle);
		case CREATE_MENU_PROXY: return gtk_create_menu_proxy (handle);
		case DAY_SELECTED: return gtk_day_selected (handle);
		case DAY_SELECTED_DOUBLE_CLICK: return gtk_day_selected_double_click (handle);
		case HIDE: return gtk_hide (handle);
		case GRAB_FOCUS: return gtk_grab_focus (handle);
		case MAP: return gtk_map (handle);
		case MONTH_CHANGED: return gtk_month_changed (handle);
		case OUTPUT: return gtk_output (handle);
		case POPUP_MENU: return gtk_popup_menu (handle);
		case PREEDIT_CHANGED: return gtk_preedit_changed (handle);
		case REALIZE: return gtk_realize (handle);
		case START_INTERACTIVE_SEARCH: return gtk_start_interactive_search (handle);
		case SELECT: return gtk_select (handle);
		case SELECTION_DONE: return gtk_selection_done (handle);
		case SHOW: return gtk_show (handle);
		case VALUE_CHANGED: return gtk_value_changed (handle);
		case UNMAP: return gtk_unmap (handle);
		case UNREALIZE: return gtk_unrealize (handle);
		default: return 0;
	}
}

以下是Button类的gtk_clicked函数

long /*int*/ gtk_clicked (long /*int*/ widget) {
	if ((style & SWT.RADIO) != 0) {//当Button类型为单选按钮时
		if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
			setSelection (!selected);
		} else {
			selectRadio ();
		}
	} else {
		if ((style & SWT.CHECK) != 0) {//当Button类型为多选按钮时
			if (grayed) {
				if (OS.gtk_toggle_button_get_active (handle)) {
					OS.gtk_toggle_button_set_inconsistent (handle, true);
				} else {
					OS.gtk_toggle_button_set_inconsistent (handle, false);
				}
			}
		}
	}
	sendSelectionEvent (SWT.Selection);
	return 0;
}


void sendSelectionEvent (int eventType) {
	sendSelectionEvent (eventType, null, false);
}




void sendSelectionEvent (int eventType, Event event, boolean send) {
	if (eventTable == null && !display.filters (eventType)) {
		return;
	}
	if (event == null) event = new Event ();
	//返回当前GTK+处理事件的副本,详细请参考http://www.gtk.org/api/2.6/gtk/gtk-General.html
	//TODO:关于底层GTK+的东西,还需要扩展
	long /*int*/ ptr = OS.gtk_get_current_event ();
	if (ptr != 0) {
		GdkEvent gdkEvent = new GdkEvent ();
		OS.memmove (gdkEvent, ptr, GdkEvent.sizeof);
		switch (gdkEvent.type) {
			case OS.GDK_KEY_PRESS:
			case OS.GDK_KEY_RELEASE: 
			case OS.GDK_BUTTON_PRESS:
			case OS.GDK_2BUTTON_PRESS: 
			case OS.GDK_BUTTON_RELEASE: {
				int [] state = new int [1];
				OS.gdk_event_get_state (ptr, state);
				setInputState (event, state [0]);
				break;
			}
		}
		OS.gdk_event_free (ptr);
	}
	sendEvent (eventType, event, send);
}

//根据事件类型封装java中的事件
void sendEvent (int eventType, Event event, boolean send) {
	if (eventTable == null && !display.filters (eventType)) {
		return;
	}
	if (event == null) event = new Event ();
	event.type = eventType;
	event.display = display;
	event.widget = this;
	if (event.time == 0) {
		event.time = display.getLastEventTime ();
	}
	if (send) {
		sendEvent (event);//将消息直接send到窗口过程

	} else {
		display.postEvent (event);//将消息post到一个先进先出的队列中(消息队列)
	}
}


////将消息post到一个先进先出的队列中(消息队列)
void postEvent (Event event) {
	/*
	* Place the event at the end of the event queue.
	* This code is always called in the Display's
	* thread so it must be re-enterant but does not
	* need to be synchronized.
	*/
	if (eventQueue == null) eventQueue = new Event [4];
	int index = 0;
	int length = eventQueue.length;
	//寻找消息队列中的一个空位置放入消息
	while (index < length) {
		if (eventQueue [index] == null) break;
		index++;
	}
	//如果当前消息队列已满,新建一个长度+4的消息队列
	if (index == length) {
		Event [] newQueue = new Event [length + 4];
		System.arraycopy (eventQueue, 0, newQueue, 0, length);
		eventQueue = newQueue;
	}
	eventQueue [index] = event;
}


//Display通过调用readAndDispatch方法,后者调用runDeferredEvents方法取出消息队列eventQueue中第一个事件
,并调用事件对应widget的sendEvent方法。

boolean runDeferredEvents () {
	boolean run = false;
	/*
	* Run deferred events.  This code is always
	* called in the Display's thread so it must
	* be re-enterant but need not be synchronized.
	*/
	while (eventQueue != null) {
		
		/* Take an event off the queue */
		Event event = eventQueue [0];
		if (event == null) break;
		int length = eventQueue.length;
		System.arraycopy (eventQueue, 1, eventQueue, 0, --length);
		eventQueue [length] = null;

		/* Run the event */
		Widget widget = event.widget;
		if (widget != null && !widget.isDisposed ()) {
			Widget item = event.item;
			if (item == null || !item.isDisposed ()) {
				run = true;
				widget.sendEvent (event);
			}
		}

		/*
		* At this point, the event queue could
		* be null due to a recursive invokation
		* when running the event.
		*/
	}

	/* Clear the queue */
	eventQueue = null;
	return run;
}

//widget的sendEvent方法
void sendEvent (Event event) {
	Display display = event.display;
	if (!display.filterEvent (event)) {
		if (eventTable != null) eventTable.sendEvent (event);
	}
}

eventTable是widget中保存事件类型和对应监听器的数据结构。eventTable根据event的type找到对应的listener,
然后执行Listener子类TypedListener的handleEvent方法
handleEvent主要的操作就是
   SelectionEvent event = new SelectionEvent (e);//对event进一步封装
   ((SelectionListener) eventListener).widgetSelected (event);//调用对应listener的回调方法。	

到此,一个响应用户事件的过程结束。这里只是记录一个过程,以后会就每一点详细讨论。


分享一个源代码学习的网站 http://grepcode.com/file/repository.grepcode.com/java/eclipse.org/4.2/org.eclipse.swt.gtk.linux/x86_64/3.100.0/org/eclipse/swt/widgets/Shell.java#Shell

你可能感兴趣的:(java)