可能是為了保持平臺(tái)獨(dú)立性,SWT沒有開放許多控件的自定義接口。例如,Win32中的Button、Label、List和ComboBox都是可以自繪(Owner Draw)的,但是SWT并沒有把這些繪制方法開放出來。在最新的3.2版本中添加的一個(gè)新特性是Table和Tree現(xiàn)在支持Custom Draw了(但是并未整合到Viewer體系中),不過對(duì)于上述控件的支持仍付闕如。
上一次,我實(shí)現(xiàn)了一個(gè)自繪的按鈕。現(xiàn)在,看到有人詢問是否可以在Combo的列表中加入圖像。其實(shí)這相當(dāng)容易,只要重載Combo Widget并把自繪接口暴露出來即可。以下是簡(jiǎn)單的代碼示例:
package?org.eclipse.swt.widgets;
import?java.io.*;
import?org.eclipse.swt.SWT;
import?org.eclipse.swt.graphics.*;
import?org.eclipse.swt.internal.win32.*;
public?class?CustomCombo?extends?Combo
{
????public?CustomCombo(?Composite?parent,?int?style?)
????{
????????super(?parent,?style?);
????????try
????????{
????????????InputStream?is?=?getClass().getResourceAsStream(?"bullet.gif"?);
????????????image?=?new?Image(?getDisplay(),?is?);
????????????is.close();
????????}
????????catch?(?IOException?e?)
????????{
????????????e.printStackTrace();
????????}
????????final?int?CB_SETITEMHEIGHT?=?0x0153;
????????OS.SendMessage(?handle,?CB_SETITEMHEIGHT,?0,?24?);
????????OS.SendMessage(?handle,?CB_SETITEMHEIGHT,?-1,?24?);
????}
????@Override
????int?widgetStyle()
????{
????????final?int?CBS_OWNERDRAWFIXED?=?0x0010;
????????final?int?CBS_HASSTRINGS?=?0x0200;
????????//?final?int?CBS_OWNERDRAWVARIABLE?=?0x0020;
????????return?super.widgetStyle()?|?CBS_OWNERDRAWFIXED?|?CBS_HASSTRINGS;
????}
????@Override
????protected?void?checkSubclass()
????{
????}
????@Override
????public?void?dispose()
????{
????????image.dispose();
????????super.dispose();
????}
????/*?@Override
????LRESULT?wmMeasureChild(?int?wParam,?int?lParam?)
????{
????????MEASUREITEMSTRUCT?mis?=?new?MEASUREITEMSTRUCT();
????????OS.MoveMemory(?mis,?lParam,?MEASUREITEMSTRUCT.sizeof?);
????????mis.itemHeight?=?40;
????????OS.MoveMemory(?lParam,?mis,?MEASUREITEMSTRUCT.sizeof?);
????????return?null;?//?super.wmMeasureChild(?wParam,?lParam?);
????}?*/
????@Override
????LRESULT?wmDrawChild(?int?wParam,?int?lParam?)
????{
????????DRAWITEMSTRUCT?dis?=?new?DRAWITEMSTRUCT();
????????OS.MoveMemory(?dis,?lParam,?DRAWITEMSTRUCT.sizeof?);
????????GC?gc?=?new?GC(?new?DCWrapper(?dis.hDC?)?);
????????Rectangle?rc?=?new?Rectangle(?dis.left,?dis.top,?dis.right?-?dis.left,
????????????????dis.bottom?-?dis.top?);
????????Display?display?=?getDisplay();
????????if?(?(dis.itemState?&?OS.ODS_SELECTED)?!=?0?)
????????{
????????????gc
????????????????????.setBackground(?display
????????????????????????????.getSystemColor(?SWT.COLOR_LIST_SELECTION?)?);
????????????gc.setForeground(?display
????????????????????.getSystemColor(?SWT.COLOR_LIST_SELECTION_TEXT?)?);
????????????gc.fillRectangle(?rc?);
????????}
????????else
????????{
????????????gc.setBackground(?display
????????????????????.getSystemColor(?SWT.COLOR_LIST_BACKGROUND?)?);
????????????gc.setForeground(?display
????????????????????.getSystemColor(?SWT.COLOR_LIST_FOREGROUND?)?);
????????????gc.fillRectangle(?rc?);
????????}
????????String?text?=?getItem(?dis.itemID?);
????????gc.drawImage(?image,?dis.left?+?1,?dis.top?+?1?);
????????gc.drawText(?text,?dis.left?+?20,?dis.top?);
????????gc.dispose();
????????return?null;
????}
????private?static?class?DCWrapper?implements?Drawable
????{
????????private?int????hdc;
????????DCWrapper(?int?hdc?)
????????{
????????????this.hdc?=?hdc;
????????}
????????public?int?internal_new_GC(?GCData?data?)
????????{
????????????return?hdc;
????????}
????????public?void?internal_dispose_GC(?int?handle,?GCData?data?)
????????{
????????}
????}
????private?Image????image;
}
值得說明的是,如果設(shè)置Combo為OwnerDraw Variable風(fēng)格,則必須重載wmMeasureChild方法來指定每一項(xiàng)的高度。如果使用OwnerDraw Fixed風(fēng)格,則只需要在構(gòu)造的時(shí)候發(fā)送一條CB_SETITEMHEIGHT消息就行了。
?另外一種值得考慮的選擇是將Win32的ComboBoxEx控件包裝成SWT Widget。不過,這需要轉(zhuǎn)換若干結(jié)構(gòu)并提供接口,Win32的ImageList管理機(jī)制和SWT的Image包裝方法差別比較大,使得這種方法實(shí)現(xiàn)起來麻煩的多。