在SWT中实现自绘Combo

在SWT中实现自绘Combo
可能是为了保持平台独立性,SWT没有开放许多控件的自定义接口。例如,Win32中的Button、Label、List和ComboBox都是可以自绘(Owner Draw)的,但是SWT并没有把这些绘制方法开放出来。在最新的3.2版本中添加的一个新特性是Table和Tree现在支持Custom Draw了(但是并未整合到Viewer体系中),不过对于上述控件的支持仍付阙如。

上一次,我实现了一个自绘的按钮。现在,看到有人询问是否可以在Combo的列表中加入图像。其实这相当容易,只要重载Combo Widget并把自绘接口暴露出来即可。以下是简单的代码示例:

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;
}


值得说明的是,如果设置Combo为OwnerDraw Variable风格,则必须重载wmMeasureChild方法来指定每一项的高度。如果使用OwnerDraw Fixed风格,则只需要在构造的时候发送一条CB_SETITEMHEIGHT消息就行了。

 另外一种值得考虑的选择是将Win32的ComboBoxEx控件包装成SWT Widget。不过,这需要转换若干结构并提供接口,Win32的ImageList管理机制和SWT的Image包装方法差别比较大,使得这种方法实现起来麻烦的多。

你可能感兴趣的:(在SWT中实现自绘Combo)