本文部分内容和灵感来自eclipse.org网站,特此声明。更多内容,请参考:
http://eclipse.org/articles/article-swt-design-1/swt-design-1.html
众所周知,swt与swing最大的不同就是它直接使用操作系统提供的现成的本地图形接口,于是具备本地化的look & feel。但是它是怎么做到这一点的呢,当然是通过jni。我们来看一个例子,假定我们使用win32的api。
我们现在有一个文本框text,通过如下的代码,我们给它一个字符串,并让它选择/highlight从3~5([3,5])的字符。
text.settext(“abcdefgh”);text.setselection(3, 6);
在windows下,这个setselection方法是怎么实现的呢?我们可以看看源码:
public void setselection (int start, int end) { … os.sendmessage (handle, os.em_setsel, start, end); os.sendmessage (handle, os.em_scrollcaret, 0, 0);}
做过windows编程的朋友可能一下子就认出了这个sendmessage,这不就是win32 api中用于向窗体发送消息的函数吗?呵呵,没错,我们再来看一下这个sendmessage方法的原型:
public static final int sendmessage (int hwnd, int msg, int wparam, int lparam) { if (isunicode) return sendmessagew (hwnd, msg, wparam, lparam); return sendmessagea (hwnd, msg, wparam, lparam);}public static final native int sendmessagew (int hwnd, int msg, int wparam, int lparam);public static final native int sendmessagea (int hwnd, int msg, int wparam, int lparam);
我们看到了两个版本,一个版本针对unicode,另一个版本针对ascii,正好win32 api也是如此,我们在这里看到的是native的方法,这意味着具体还有一组jni的c代码来直接与操作系统的函数打交道:
#ifndef no_sendmessagew__iiiijniexport jint jnicall os_native(sendmessagew__iiii) (jnienv *env, jclass that, jint arg0, jint arg1, jint arg2, jint arg3){ jint rc; os_native_enter(env, that, sendmessagew__iiii_func); rc = (jint)sendmessagew((hwnd)arg0, arg1, (wparam)arg2, (lparam)arg3); os_native_exit(env, that, sendmessagew__iiii_func); return rc;}#endif#ifndef no_sendmessagea__iiiijniexport jint jnicall os_native(sendmessagea__iiii) (jnienv *env, jclass that, jint arg0, jint arg1, jint arg2, jint arg3){ jint rc; os_native_enter(env, that, sendmessagea__iiii_func); rc = (jint)sendmessagea((hwnd)arg0, arg1, (wparam)arg2, (lparam)arg3); os_native_exit(env, that, sendmessagea__iiii_func); return rc;}#endif
看到这里,你也许已经恍然大悟:swt所做的无非就是把win32的api简单的包装了一下,我们在swt这一层调用的方法、传递的参数被原封不动的代理到了win32层。这就是swt的核心思想。swt有一个很重要的设计原则,那就是,swt的api一对一的封装os的api,完全忠实于操作系统的api实现的行为,如果有bug,那也是os的bug,它不会尝试去“纠正”操作系统,因为那样会潜在的破坏本地化的一些行为。忠实于os也使得调用者不必但心自己的swt程序会跟os的本地gui有不一致的地方,如有必要直接参考msdn即可。swt其实就是这样一个thin wrapper,我们通过它可以方便的访问win32的图形api,为我们的应用程序提供native的look & feel。
下面给出一个完整的swt示例:
package sean.test.swt;import org.eclipse.swt.swt;import org.eclipse.swt.layout.filllayout;import org.eclipse.swt.widgets.display;import org.eclipse.swt.widgets.shell;import org.eclipse.swt.widgets.text;public class dummyswt { public static void main(string[] args) { final display display = new display(); final shell shell = new shell(display); shell.setlayout(new filllayout()); final text text = new text(shell, swt.single); text.settext("abcdefgh"); text.setselection(3, 6); shell.pack(); shell.open(); while (!shell.isdisposed()) { if (!display.readanddispatch()) { display.sleep(); } } display.dispose(); }}
