BaNg@taobao

Just Do It!

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  20 Posts :: -1 Stories :: 202 Comments :: 0 Trackbacks
对于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
 3IF x.%DEV_TOOLS%==x. set DEV_TOOLS=c:\PROGRA~1
 4call %DEV_TOOLS%\MICROS~2\vc98\bin\vcvars32.bat
 5IF x.%MSSDK%==x. set MSSDK=%DEV_TOOLS%\MICROS~3
 6call %MSSDK%\setenv /XP32 /RETAIL
 7IF x.%OUTPUT_DIR%==x. set OUTPUT_DIR=..\out
 8IF x.%JAVA_HOME%==x. set JAVA_HOME=%DEV_TOOLS%\Java\jdk1.6.0_06
 9IF x.%XULRUNNER_SDK%==x. set XULRUNNER_SDK=C:\gecko-sdk
10set XULRUNNER_MAKE=make_xulrunner
11IF x.%1==x.x86 shift
12GOTO 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
 2JNIEXPORT 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
 5const wchar_t* wcTitle=L"Hello";
 6const wchar_t* wcContent=L"World";
 7const wchar_t* wcName = L"Bang";
 8
 9LRESULT 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
35JNIEXPORT 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来实现!

 

posted on 2008-07-24 18:39 Always BaNg. 阅读(1965) 评论(1)  编辑  收藏 所属分类: JavaEclipseC++

Feedback

# re: 通过一个小例子看怎样扩展SWT 2008-09-01 17:50 zhuxing
新鲜,改天也玩玩  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: