SWT源码分析 (一)

 

阅读本文需要知道搭建swt的开发环境,对SWT有基本的了解,最好对Windows api也有所了解,还要稍微了解一下JNI。

 

 

HelloSWT是一个基本的SWT程序,当点击输入框的时候,会弹出一个MessageBox。

 

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

class HelloSWT {
public static void main(String[] args) {
Display display = new Display();// 创建一个display对象。
final Shell shell = new Shell(display);// shell是程序的主窗体
shell.setLayout(null); // 设置shell的布局方式
Text hello = new Text(shell, SWT.MULTI); // 声明一个可以显示多行信息的文本框
shell.setText("Java应用程序"); // 设置主窗体的标题
shell.setSize(200, 100); // 设置主窗体的大小
Color color = new Color(Display.getCurrent(), 255, 255, 255);// 声明颜色对象
shell.setBackground(color); // 设置窗体的背景颜色
hello.setText("Hello, SWT World!\n\n你好,SWT世界!");// 设置文本框信息
hello.pack(); // 自动调整文本框的大小
shell.pack(); //自动调整主窗体的大小
shell.open(); // 打开主窗体

hello.addMouseListener(new MouseListener() {

@Override
public void mouseUp(MouseEvent e) {
// TODO Auto-generated method stub
MessageBox box = new MessageBox(shell);
box.setMessage("内容");
box.setText("标题");
box.open();
}

@Override
public void mouseDown(MouseEvent e) {
// TODO Auto-generated method stub

}

@Override
public void mouseDoubleClick(MouseEvent e) {
// TODO Auto-generated method stub

}
});
while (!shell.isDisposed()) { // 如果主窗体没有关闭则一直循环
if (!display.readAndDispatch()) { // 如果display不忙
display.sleep(); // 休眠
}
}
display.dispose(); // 销毁display
}
}

 

运行效果:

 


这个程序也是我们分析SWT运行的一个介入点。程序中为hello这个Text增加了鼠标事件的监听器,在 MessageBox box = new MessageBox(shell);这一行加上一个断点,因为可以肯定,在点击鼠标时,会执行这段代码,可以通过断点观察出前后程序执行的顺序。当在Text上点击鼠标时,会在断点处暂停,此时运行的上下文为:

 

 

从这里就可以看出程序的执行过程了,先从main方法开始,HelloSWT的51行为 if (!display.readAndDispatch()):

 

		while (!shell.isDisposed()) { // 如果主窗体没有关闭则一直循环
			if (!display.readAndDispatch()) { // 如果display不忙
				display.sleep(); // 休眠
			}
		}
		display.dispose(); // 销毁display

 

 readAndDispatch方法在API中的说明为:

 

 

Reads an event from the operating system's event queue, dispatches it appropriately, and returns true if there is potentially more work to do, or false if the caller can sleep until another event is placed on the event queue.

In addition to checking the system event queue, this method also checks if any inter-thread messages (created by syncExec() or asyncExec()) are waiting to be processed, and if so handles them before returning. 

 

从操作系统的事件队列里面读取一个事件,并做适当的分发,返回true时表示有工作要做,返回false表示没有接受到事件。...

当点击鼠标时,程序接收到相应的事件,readAndDispatch()就会返回true。

readAndDispatch的实现为:

 

public boolean readAndDispatch () {
	checkDevice ();
	lpStartupInfo = null;
	drawMenuBars ();
	runSkin ();
	runDeferredLayouts ();
	runPopups ();
	if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) {
		if (!filterMessage (msg)) {
			OS.TranslateMessage (msg);
			OS.DispatchMessage (msg);
		}
		runDeferredEvents ();
		return true;
	}
	return isDisposed () || (runMessages && runAsyncMessages (false));
}

 

 

方法开始调用了一些其他函数,从名称上来看是做了一些检查和界面显示、菜单的相关操作,我们现在不关心这些,重点看这里:

 

	if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) {
		if (!filterMessage (msg)) {
			OS.TranslateMessage (msg);
			OS.DispatchMessage (msg);
		}
		runDeferredEvents ();
		return true;
	}

 

 这里出现一个OS类,OS类是SWT内部的一个类,里面定义了很多native方法,我们知道SWT底层通过JNI调用了很多本地的windows api,所以程序的界面和本地的windows程序几乎是一样的,而Swing做出来的界面和具体的平台没关系,和一般的windows程序风格不一样,总是让人感觉不习惯。

OS类如下:

 

public class OS extends C {
	static {
		Library.loadLibrary ("swt"); //$NON-NLS-1$
	}
	......

 

 可见OS类中通过Library.loadLibrary ("swt")加载本地的dll,可以继续进入loafLibrary方法内部,最后得知

加载的是swt-win32-xxxx.dll 。xxxx是eclipse的版本号。在我的机器上是swt-win32-3650.dll。这个dll在eclipse安装目录下的plugins目录中的org.eclipse.swt.win32.win32.x86_3.6.0.v3650b.jar中。还有一个org.eclipse.swt.win32.win32.x86.source_3.6.0.v3650b.jar,里面是swt的源码。解压这个源码的jar之后,可以看到一个os.c文件,我猜测,OS类的native方法的实现就是在os.c中,并没有去验证。

os.c 的部分代码:

 

#include "swt.h"
#include "os_structs.h"
#include "os_stats.h"

#define OS_NATIVE(func) Java_org_eclipse_swt_internal_win32_OS_##func

......

#ifndef NO_PeekMessageA
JNIEXPORT jboolean JNICALL OS_NATIVE(PeekMessageA)
	(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jint arg2, jint arg3, jint arg4)
{
	MSG _arg0, *lparg0=NULL;
	jboolean rc = 0;
	OS_NATIVE_ENTER(env, that, PeekMessageA_FUNC);
	if (arg0) if ((lparg0 = getMSGFields(env, arg0, &_arg0)) == NULL) goto fail;
	rc = (jboolean)PeekMessageA(lparg0, (HWND)arg1, arg2, arg3, arg4);
fail:
	if (arg0 && lparg0) setMSGFields(env, arg0, lparg0);
	OS_NATIVE_EXIT(env, that, PeekMessageA_FUNC);
	return rc;
}
#endif

 

不同函数的定义都是类似:

 JNIEXPORT jboolean JNICALL OS_NATIVE(PeekMessageA)

(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jint arg2, jint arg3, jint arg4)

 

其中OS_NATIVE是一个宏,以上函数实际的定义为:

 

JNIEXPORT jboolean JNICALL Java_org_eclipse_swt_internal_win32_OS_PeekMessageA

(JNIEnv *env, jclass that, jobject arg0, jintLong arg1, jint arg2, jint arg3, jint arg4)

 

 

函数名为 :java中的包名_类名_方法名。这种格式是JNI要求的。

 

现在知道了,SWT调用OS类的static native方法就相当于直接调用了Windows SDK Api。

回到Display类中,OS.PeekMessage的作用是从系统的消息队列取消息,如果取到了消息就返回true。

 

OS.TranslateMessage (msg);将消息进行一些转化。

OS.DispatchMessage (msg);将消息发送给相应的窗口。

 

这几个都是windows api 函数,不清楚也不要紧,这些是每个windows程序都有的,后面我会贴出一个最简单的

windows c程序。

 

随后是runDeferredEvents ()函数,函数如下:

 

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;
}

 作用是从SWT的 eventQuene中取出一个事件(事件是怎么放入到eventQueue中的呢?后面说),找到事件对应的控件,让这个控件去处理这个事件。

 

到现在分析到前面断点那个图的第三步,后面的过程会继续分析。

未完待续。

Kettle 是一款功能强大的 ETL 工具,其源码主要分为以下几个部分: 1. 核心引擎:该部分代码位于 `core` 包下,包括了大量的类和接口,用于执行各种 ETL 操作。其中,`org.pentaho.di.trans.Trans` 类是最核心的类,表示一个转换(Transformation),可以执行所有的 ETL 操作。 2. 数据源和目标插件:该部分代码位于 `plugins` 包下,包括了各种数据源和目标插件,如 MySQL 插件、Hadoop 插件、文件插件等。每个插件都有自己的 `Input` 和 `Output` 类,用于读取和写入数据。 3. 步骤插件:该部分代码位于 `steps` 包下,包括了各种步骤插件,如转换步骤(Transformation Step)、过滤器步骤(Filter Step)、排序步骤(Sort Step)等。每个步骤都有自己的 `Step` 类,用于执行具体的操作。 4. 转换元数据:该部分代码位于 `metadata` 包下,包括了各种转换元数据,如数据库连接、文件路径、参数等。每个元数据都有自己的类,用于存储和管理相关信息。 5. UI:该部分代码位于 `ui` 包下,包括了 Kettle 的用户界面。Kettle 采用 SWT 技术实现界面,其中 `org.pentaho.di.ui.spoon.Spoon` 类是最核心的类,表示 Kettle 的主界面。 总体来说,Kettle 的源码比较庞大,但其代码结构清晰,模块化程度高,易于维护和扩展。如果想深入了解 Kettle 的运行机制和实现细节,可以从以上几个方面入手,逐步深入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值