通过一个小例子看怎样扩展SWT

通过一个小例子看怎样扩展SWT
对于Eclipse开发者来说,不管Plug-in还是RCP免不了要和SWT打交道,但两者似乎有些不同,Plug-in主要跟Eclipse过招,开发更多是上层应用如UI/JDT/EMF/GMF等,而RCP像是应用程序,时不时与图形系统交互,需求更是五花八门,举几例:
  • RCP界面要跟Office 2007/Vista一样。
  • 我喜欢上一VC版的水晶按钮。
  • 商业版控件支持。
  • 我的RCP程序要定时启动。
这些效果让RCP下的SWT越来越跟平台相关,但矛盾的是SWT要跨平台,提供的API只能是一个平衡产品+少许补充,更多特性依赖我们对SWT进行扩展。比较常见的是对SWT Win32 API进行扩展,因为Windows的图形特性太丰富了,不用白不用啊。

下面就以SWT win32 x86来演示一下这个扩展过程。扩展很简单,就是在swt的窗口上加一个自定义系统菜单,最终效果如下图:



首先要有SWT JNI源代码,在Eclipse plug-in目录下找到org.eclipse.swt.win32.win32.x86.source_3.X.X.vXXX.jar(xx为版本号),解压缩到c:\build\swt-jni,解完后在会发现有一堆h和c文件,其中比较重要的就是os, gdip, xpcom,wgl,awt,用途分别如下:
  • os: 主要的JNI,用来创建控件,事件处理等。
  • gdip: 与windows的dc交互,提供swt的gc画图功能。
  • xpcom: 供swt调用mozilla系列浏览器如firefox等。
  • wgl: 与3D相关,一般都用不上。
  • awt:在swt中调用awt,awt也是jni。
了解swt源代码之后,接下来为build swt做准备。
  • 安装vc6,尝试过用高版本,但不支持。
  • 安装platform SDK 2003 February版,下载地址  遵照安装说明将SDK解压缩安装。不要尝试更新版本,不支持。
  • 安装jdk,这个无所谓,1.4, 1.5, 1.6都可以。
  • 下载gecko-sdk(下载地址),请务必使用1.8,swt目前不完全支持1.9。

所以的工具都安装或解压之后,在swt源代码目录下找到build.bat,在:X86 label部分做如下配置,其中配置的目录视你的安装而定:

 1 :X86
 2
 3 IF x.%DEV_TOOLS% == x. set DEV_TOOLS = c:\PROGRA~ 1
 4 call %DEV_TOOLS%\MICROS~ 2 \vc98\bin\vcvars32.bat
 5 IF x.%MSSDK% == x. set MSSDK = %DEV_TOOLS%\MICROS~ 3
 6 call %MSSDK%\setenv /XP32 /RETAIL
 7 IF x.%OUTPUT_DIR% == x. set OUTPUT_DIR = ..\out
 8 IF x.%JAVA_HOME% == x. set JAVA_HOME = %DEV_TOOLS%\Java\jdk1 .6 .0_ 06
 9 IF x.%XULRUNNER_SDK% == x. set XULRUNNER_SDK = C:\gecko-sdk
10 set XULRUNNER_MAKE = make_xulrunner
11 IF x.% 1 == x.x86 shift
12 GOTO MAKE


如果你和我一样的用的是Sun的JDK,且版本是1.5或1.6,还须修改一下和build.bat同目录的make_win32.mak文件。

替换

AWT_LIBS    =   " $(JAVA_HOME)\jre\bin\jawt.lib "

AWT_LIBS    =   " $(JAVA_HOME)\lib\jawt.lib "


一旦配置完成后,就可以在命令行中运行 build.bat x86 来build swt了,如果你的build过程中出错,使用build x86 clean删除垃圾文件,然后再查明原因。如果没有错误的话,目录下会生成5个dll文件,分别是swt-awt-win32-XXXX.dll, swt-gdip-win32-XXXX.dll, swt-wgl-win32-XXXX.dll, swt-win32-XXXX.dll, swt-xulrunner-win32-XXXX.dll,其中XXXX是视你的Eclipse版本而定。

要实现我们想要的效果,还需针对SWT的消息处理程序(WndProc) 扩展一下OS,那就是在就在主窗口建立过程中候往系统菜单里面加一自定义项。在Win32中,窗口建立的消息为WM_CREATE(值为1)。为简单起见,这里只是覆盖了SWT的默认消息处理程序,它通过os.c中的 OS_NATIVE(DefWindowProcW)方法来实现的(在98以后的版本api都是unicode,所以只覆盖W版本)

改动之前:

 1 #ifndef NO_DefWindowProcW
 2 JNIEXPORT jint JNICALL OS_NATIVE(DefWindowProcW)
 3     (JNIEnv  * env, jclass that, jint arg0, jint arg1, jint arg2, jint arg3)
 4 {
 5    jint rc = 0;
 6    OS_NATIVE_ENTER(env, that, DefWindowProcW_FUNC);
 7    rc = (jint)DefWindowProcW((HWND)arg0, arg1, (WPARAM)arg2, (LPARAM)arg3);
 8    OS_NATIVE_EXIT(env, that, DefWindowProcW_FUNC);
 9    return rc;
10}

11 #endif

改动之后:

 1 #ifndef NO_DefWindowProcW
 2
 3 #define  ID_CUSTOM_MENU 32888
 4
 5 const  wchar_t *  wcTitle = L " Hello " ;
 6 const  wchar_t *  wcContent = L " World " ;
 7 const  wchar_t *  wcName  =  L " Bang " ;
 8
 9 LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
10 {
11    int wmId, wmEvent;
12    HMENU hSysMenu;
13    switch (message)
14    {
15    case WM_CREATE:
16        hSysMenu = GetSystemMenu(hWnd,FALSE);
17        InsertMenuW(hSysMenu,1,MF_BYPOSITION | MF_STRING,ID_CUSTOM_MENU,wcName);
18        break;
19    case WM_DESTROY:
20        PostQuitMessage(0);
21        break;
22    case WM_SYSCOMMAND:
23        wmId = LOWORD(wParam);
24        if (wmId==ID_CUSTOM_MENU)
25            MessageBoxW(hWnd,wcTitle,wcContent,MB_OK);
26        else
27            return DefWindowProcW(hWnd, message, wParam, lParam);
28        break;
29    default:
30        return DefWindowProcW(hWnd, message, wParam, lParam);
31    }

32    return 0;
33}

34
35 JNIEXPORT jint JNICALL OS_NATIVE(DefWindowProcW)
36     (JNIEnv  * env, jclass that, jint arg0, jint arg1, jint arg2, jint arg3)
37 {
38    jint rc = 0;
39    OS_NATIVE_ENTER(env, that, DefWindowProcW_FUNC);
40    rc = (jint)MyWndProc((HWND)arg0, arg1, (WPARAM)arg2, (LPARAM)arg3);
41    OS_NATIVE_EXIT(env, that, DefWindowProcW_FUNC);
42    return rc;
43}

44
45 #endif

改动的目的就是在系统菜单里面加了一个菜单项 "Bang",点击后会出现“Hello world” 对话框。

重新在swt源目录下运行build x86,生成的swt就是扩展以后的版本。

现在我们来测试一下效果,写一个如下所示的HelloWorld1.java,放到swt源目录下,先运行javac HelloWorld1.java,再运行java HelloWorld1。不用担心classpath与library path,build之后它们默认都在当前目录下。

import  org.eclipse.swt.widgets. * ;

public   class  HelloWorld1  {

public static void main (String [] args) {
    Display display 
= new Display ();
    Shell shell 
= new HelloWorld1 ().open (display);
    
while (!shell.isDisposed ()) {
        
if (!display.readAndDispatch ()) display.sleep ();
    }

    display.dispose ();
}

    
public Shell open (Display display) {
    Shell shell 
= new Shell (display);
    shell.open ();
    
return shell;
}

}


在窗口标题栏单击右键,点击出现的Bang菜单会有如下效果图:



这个例子虽然简单,但大致描述了扩展swt的过程,更复杂的扩展等待YOU来实现!

 

你可能感兴趣的:(通过一个小例子看怎样扩展SWT)