`
edgar108
  • 浏览: 33453 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

SWT源码分析 (六)

阅读更多

第一篇文章中,有一个问题我没有解释,在Display中的runDeferedEvents方法中:

 

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 invocation
		* when running the event.
		*/
	}

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

 事件event是从eventQueue中取出来的,eventQueue是Display中的一个Event数组:

 

Event [] eventQueue;

 我自然就会想到,系统中的各种事件,是怎么放入这个eventQueue中的呢?

继续从上文的按钮程序入手,现在监听按钮1的鼠标按下事件:

 

package com.edgar;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

class TestMultButton {
        public static void main(String[] args) {
                Display display = new Display();// 创建一个display对象。
                final Shell shell = new Shell(display);// shell是程序的主窗体
                shell.setText("Java应用程序"); // 设置主窗体的标题
                shell.setSize(300, 300); // 设置主窗体的大小
                
                Button b1 = new Button(shell,SWT.NONE);
                b1.setText("按钮1");
                b1.setBounds(100,50, 100, 50);
                Button b2 = new Button(shell,SWT.NONE);
                b2.setText("按钮2");
                b2.setBounds(100,150, 100, 50);     
                b1.addMouseListener(new MouseAdapter() {
					@Override
					public void mouseDown(MouseEvent e) {
						// TODO Auto-generated method stub
						System.out.println("mousedown");
					}
		
				});
                shell.open(); // 打开主窗体
                
                while (!shell.isDisposed()) { // 如果主窗体没有关闭则一直循环
                        if (!display.readAndDispatch()) { // 如果display不忙
                                display.sleep(); // 休眠
                        }
                }
                display.dispose(); // 销毁display
        }
}

 我在System.out.println("mousedown");这行代码加上断点,然后运行程序,然后点击按钮一,程序暂停,运行上下文如下:



 程序执行的流程和分析一中的一样,我们并没有看到上下文中看到windowProc,这是“意料之中”的,因为我们在利用SWT这个GUI类库编程,几乎搜有GUI类库都会对消息循环,窗口过程函数进行封装,让我们能以OO的方式来编程。现在为了知道SWT是怎么进行封装的,我找到Control类中的 windowProc 方法:

 

int /*long*/ windowProc (int /*long*/ hwnd, int msg, int /*long*/ wParam, int /*long*/ lParam) {
	LRESULT result = null;
	switch (msg) {
		......
		case OS.WM_KILLFOCUS:			result = WM_KILLFOCUS (wParam, lParam); break;
		case OS.WM_LBUTTONDBLCLK:		result = WM_LBUTTONDBLCLK (wParam, lParam); break;
		case OS.WM_LBUTTONDOWN:			result = WM_LBUTTONDOWN (wParam, lParam); break;
		case OS.WM_LBUTTONUP:			result = WM_LBUTTONUP (wParam, lParam); break;
		......
	}
	if (result != null) return result.value;
	return callWindowProc (hwnd, msg, wParam, lParam);
}

 对应左键点击按钮来说,windowProc中会接收到WM_LBUTTONDOWN消息,然后会调用WM_LBUTTONDOWN(wParam,lParam)函数,所以我在WM_LBUTTONDOWN函数加一个断点:



 运行程序,点击按钮一后,程序果然停在return wmLButtonDown (handle, wParam, lParam);这行!

 

现在我们就进入wmLButtonDown(handle,wParam,lParam)方法里面,看看都有什么操作:

 

LRESULT wmLButtonDown (int /*long*/ hwnd, int /*long*/ wParam, int /*long*/ lParam) {
	Display display = this.display;
	LRESULT result = null;
	int x = OS.GET_X_LPARAM (lParam);
	int y = OS.GET_Y_LPARAM (lParam);
	boolean [] consume = null, detect = null;
	boolean dragging = false, mouseDown = true;
	int count = display.getClickCount (SWT.MouseDown, 1, hwnd, lParam);
	if (count == 1 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
		if (!OS.IsWinCE) {
			/*
			* Feature in Windows.  It's possible that the drag
			* operation will not be started while the mouse is
			* down, meaning that the mouse should be captured.
			* This can happen when the user types the ESC key
			* to cancel the drag.  The fix is to query the state
			* of the mouse and capture the mouse accordingly.
			*/
			detect = new boolean [1];
			consume = new boolean [1];
			dragging = dragDetect (hwnd, x, y, true, detect, consume);
			if (isDisposed ()) return LRESULT.ZERO;
			mouseDown = OS.GetKeyState (OS.VK_LBUTTON) < 0;
		}
	}
	display.captureChanged = false;
	boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);
	if (dispatch && (consume == null || !consume [0])) {
		result = new LRESULT (callWindowProc (hwnd, OS.WM_LBUTTONDOWN, wParam, lParam));	
	} else {
		result = LRESULT.ZERO;
	}
	if (OS.IsPPC) {
		/*
		* Note: On WinCE PPC, only attempt to recognize the gesture for
		* a context menu when the control contains a valid menu or there
		* are listeners for the MenuDetect event.
		*/
		Menu menu = getMenu ();
		boolean hasMenu = menu != null && !menu.isDisposed ();
		if (hasMenu || hooks (SWT.MenuDetect)) {
			SHRGINFO shrg = new SHRGINFO ();
			shrg.cbSize = SHRGINFO.sizeof;
			shrg.hwndClient = hwnd;
			shrg.ptDown_x = x;
			shrg.ptDown_y = y; 
			shrg.dwFlags = OS.SHRG_RETURNCMD;
			int type = OS.SHRecognizeGesture (shrg);
			if (type == OS.GN_CONTEXTMENU) showMenu (x, y);
		}
	}
	if (mouseDown) {
		if (!display.captureChanged && !isDisposed ()) {
			if (OS.GetCapture () != hwnd) OS.SetCapture (hwnd);
		}
	}
	if (dragging) {
		sendDragEvent (1, x, y);
	} else {
		if (detect != null && detect [0]) {
			/*
			* Feature in Windows.  DragDetect() captures the mouse
			* and tracks its movement until the user releases the
			* left mouse button, presses the ESC key, or moves the
			* mouse outside the drag rectangle.  If the user moves
			* the mouse outside of the drag rectangle, DragDetect()
			* returns true and a drag and drop operation can be
			* started.  When the left mouse button is released or
			* the ESC key is pressed, these events are consumed by
			* DragDetect() so that application code that matches
			* mouse down/up pairs or looks for the ESC key will not
			* function properly.  The fix is to send the missing
			* events when the drag has not started.
			* 
			* NOTE: For now, don't send a fake WM_KEYDOWN/WM_KEYUP
			* events for the ESC key.  This would require computing
			* wParam (the key) and lParam (the repeat count, scan code,
			* extended-key flag, context code, previous key-state flag,
			* and transition-state flag) which is non-trivial.
			*/
			if (OS.GetKeyState (OS.VK_ESCAPE) >= 0) {
				OS.SendMessage (hwnd, OS.WM_LBUTTONUP, wParam, lParam);
			}
		}
	}
	return result;
}

 方法有点长,但是真正执行的地方并不长。一开始得到点击事件的x坐标和y坐标,然后得到点击的次数,然后调用sendMouseEvent方法:

 

boolean dispatch = sendMouseEvent (SWT.MouseDown, 1, count, 0, false, hwnd, OS.WM_LBUTTONDOWN, wParam, lParam);

 看方法的名字是“发送鼠标事件”进入该方法:

 

boolean sendMouseEvent (int type, int button, int count, int detail, boolean send, int /*long*/ hwnd, int msg, int /*long*/ wParam, int /*long*/ lParam) {
	if (!hooks (type) && !filters (type)) return true;
	Event event = new Event ();
	event.button = button;
	event.detail = detail;
	event.count = count;
	event.x = OS.GET_X_LPARAM (lParam);
	event.y = OS.GET_Y_LPARAM (lParam);
	setInputState (event, type);
	mapEvent (hwnd, event);
	if (send) {
		sendEvent (type, event);
		if (isDisposed ()) return false;
	} else {
		postEvent (type, event);
	}
	return event.doit;
}

 我们看到方法里面将系统的消息 “转换”成了SWT自己的事件对象。给event对象的属性赋值之后,因为send的值是false(看调用的代码和形参对应起来!),所以调用postEvent(type,event)方法:

 

void postEvent (int eventType, Event event) {
	sendEvent (eventType, event, false);
}

 又调用了sendEvent方法:

 

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);
	} else {
		display.postEvent (event);
	}
}

 给属性赋值之后,因为send是false,继续调用display.postEvent(event):

 

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++;
	}
	if (index == length) {
		Event [] newQueue = new Event [length + 4];
		System.arraycopy (eventQueue, 0, newQueue, 0, length);
		eventQueue = newQueue;
	}
	eventQueue [index] = event;
}

 postEvent方法,正是把此时的事件event存入了eventQueue。好了,文章一遗留的问题解决了。

  • 大小: 12.1 KB
  • 大小: 7.3 KB
分享到:
评论

相关推荐

    SWT源码 swt.jar

    SWT源码的获取和分析对于开发者来说非常有价值,因为它可以深入理解其工作原理,自定义组件或优化应用程序。 "swt.jar"文件是SWT库的二进制版本,包含了运行SWT应用所需的类和资源。这个jar包通常会被Java项目引用...

    图书馆管理系统SWT源码

    《图书馆管理系统SWT源码详解》 在信息技术领域,开发高效、用户友好的管理软件是提升工作效率的关键。本文将深入探讨一个特别的案例——“图书馆管理系统”,该系统采用SWT(Standard Widget Toolkit)进行设计,...

    SWT API 帮助文档 及源码

    **源码分析** SWT 的源码是用Java编写的,通过JNI(Java Native Interface)与操作系统底层交互。通过阅读源码,开发者可以深入理解SWT的工作原理,学习如何与本地系统进行通信,以及如何优化GUI性能。源码中包含了...

    SWT内嵌火狐浏览器源码

    5. **源码分析与使用**: 源码中可能包含了如何初始化和控制SWT_Browser实例,如何加载和导航网页,以及如何处理JavaScript与Java之间的交互的示例代码。开发者可以通过学习和理解这些源码,了解如何在自己的项目中...

    eclipse swt项目源代码

    源代码对于学习和理解SWT和JFace的工作原理极其有用,开发者可以通过阅读源码学习如何使用这些库,或者进行二次开发。 6. `about_files`:这个目录可能包含了Eclipse关于对话框显示的其他资源文件,如图标、语言...

    swt源代码有兴趣的朋友不能错过哦!呵呵,好东西哦!

    通过分析这些源代码,开发者可以了解SWT如何与操作系统进行底层交互,实现高效、原生的GUI效果。这对于希望优化SWT性能、定制特定功能或者学习GUI编程原理的开发者来说,是非常宝贵的资料。如果你对SWT感兴趣,那么...

    Kettle 4.4.2源码分析.docx

    Kettle 4.4.2源码分析 Kettle 是一款功能强大且流行的数据 Integrator 工具,它提供了多种数据处理和Integration 功能。本文档将对 Kettle 4.4.2 的源码进行分析,从源码获取和编译到修改 Kettle 界面和启动测试等...

    Java SWT 简单 拼图 游戏 源码

    Java SWT(Standard Widget Toolkit)是Java编程环境中...通过学习和分析这个源码,你可以深入理解Java SWT的用法,以及如何结合算法实现一个完整的桌面应用程序。此外,对于游戏设计和用户交互也有一定的学习价值。

    eclipse swt/jface 核心应用源码

    掌握它们的使用和源码分析能力,对于提升 Java GUI 开发技能和参与 Eclipse RCP 应用的开发具有重要意义。通过深入研究提供的源码,开发者可以更好地优化自己的代码,实现更加高效和用户友好的界面。

    JAVA CS SWT RCP 在线升级 自动更新 源码

    5. **源码分析**:在提供的压缩包中,`com.cxd.zxsj`、`com.cxd.zxsj.feature`和`com.cxd.zxsj.update`可能分别代表了项目的主代码包、功能描述文件和更新相关配置。`com.cxd.zxsj`可能是应用程序的主要代码结构,...

    SWT-JFace Code源码

    通过分析这些源码,开发者可以学习到如何实际应用 SWT 和 JFace 创建高效、美观的 GUI 应用。例如,Chapter09可能介绍了布局管理,包括如何使用GridLayout、FillLayout等;Chapter13可能涉及事件处理和监听器;...

    SWT Tree 完整的树例子源码

    首先,我们来分析给定的文件列表: 1. `otree.css`: 这个文件是CSS样式表,用于定义SWT Tree的外观和布局,如字体、颜色、边框等。在创建树形结构时,可以利用CSS定制节点的样式,使其更具视觉吸引力。 2. `otree....

    SWT扩展

    源码分析** 对于SWT的深入学习,阅读源码是一个有效的途径。了解SWT如何与操作系统进行交互,以及如何实现各种控件和功能,可以帮助开发者更好地优化应用性能,解决特定问题。 在实际项目中,SWT常用于开发桌面...

    SWT开发

    7. **源码阅读**:了解SWT源码有助于深入理解其工作机制,解决性能问题或自定义组件。 8. **开发工具**:Eclipse是主要的SWT开发环境,提供代码补全、调试、布局编辑等功能。除此之外,还有SWTBot用于自动化测试,...

    swt

    博客链接中的内容可能涉及对SWT源码的分析。SWT作为一个开源项目,其源码对于开发者来说是一个宝贵的资源,可以深入理解其内部工作机制,学习如何与操作系统进行交互,以及如何优化GUI性能。通过阅读源码,开发者...

    kettle4.1源码分析

    Kettle4.1 是该工具的一个版本,其源码分析有助于深入理解其内部工作原理,便于自定义开发或优化。 在开始源码分析之前,首先需要获取和编译 Kettle4.1 的源码。这可以通过 SVN 从官方仓库中下载,网址为 svn://...

    Java+SWT+图形用户界面教程+PDFJava源码

    通过分析和运行这些代码,你可以深入理解SWT的API和组件使用方式,以及如何将它们整合到Java应用程序中。 SWT提供了一系列的控件,包括按钮、文本框、列表、树、表格等,这些都可以用来构建各种复杂的用户界面。...

    JAVA SWT 多标签浏览器

    JAVA SWT 多标签浏览器是一种利用Java编程语言和SWT(Standard Widget Toolkit)库构建...通过分析源码,开发者可以学习到如何利用SWT创建原生外观的应用,以及如何实现复杂的用户交互功能,比如多标签导航和书签管理。

    以SWT为界面,用POI读取、修改excel文件(源码)

    标题中的“以SWT为界面,用POI读取、修改excel文件(源码)”指的是一个Java编程项目,它利用了两种主要的技术:SWT(Standard Widget Toolkit)和Apache POI,来创建用户界面并处理Microsoft Excel文件。下面将详细...

Global site tag (gtag.js) - Google Analytics