本文部分内容和灵感来自 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__IIII JNIEXPORT 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__IIII JNIEXPORT 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(); } }