天天看點

WTL 自繪控件庫 (CQsCheckBox)

概述:

代碼實作如下:

#pragma once;
#include "QsInclude.h"

#define     TXTMAX                  512    //支援最大字型長度 
#define   QS_CHK_SYSYSTEM       0x00000001      //CheckBox系統樣式
#define     QS_CHK_OWNERDRAW        0x00000002          //CheckBox自繪樣式,預設為自繪樣式。

class CQsCheckBox:
  public CWindowImpl<CQsCheckBox, CButton>,
  public CImageMgrCtrlBase< CQsCheckBox>,
  public COwnerDraw< CQsCheckBox >
{
  typedef CWindowImpl< CQsCheckBox, CButton > theBaseClass;
  typedef CImageMgrCtrlBase< CQsCheckBox> theImageCtrlBaseClass;

  Image *m_pCurImage;                     //目前正在使用的圖檔
  Image *m_pLastImage;                    //發生狀态改變前使用的圖檔
  volatile int m_nCheck;             //是否被選中标志
  volatile bool m_bMouseDown;         //滑鼠左鍵按下
  StringAlignment m_eAlignment;   // CheckBox的方向
  Color m_enableColor;                       //可用狀态時字型的顔色
  Color m_unenableColor;                  //不可用狀态時字型的顔色。
  DWORD m_dwStyle;
  BOOL    m_bunifyfont;
public:
  BEGIN_MSG_MAP( CQsCheckBox )
    MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBKGnd )
    //MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown )
     MESSAGE_HANDLER( WM_LBUTTONUP, OnLButtonUp )
    MESSAGE_HANDLER( WM_MOUSELEAVE, OnMouseLeave )
    MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
    MESSAGE_HANDLER( BM_SETCHECK, OnSetCheck )
    MESSAGE_HANDLER( BM_GETCHECK, OnGetCheck )
    //REFLECTED_COMMAND_CODE_HANDLER( BN_CLICKED, OnClicked )
    CHAIN_MSG_MAP_ALT( COwnerDraw< CQsCheckBox >, 1 )
    CHAIN_MSG_MAP( theImageCtrlBaseClass )
    DEFAULT_REFLECTION_HANDLER()
  END_MSG_MAP()

  /**
  *@method   CQsCheckBox
  *@brief     CQsCheckBox類構造函數
  *    
  *@return   
  */
  CQsCheckBox():
    m_bMouseDown( false ),
    m_pCurImage( NULL ),
    m_pLastImage( NULL ),
    m_enableColor(255, 0, 0, 0),
    m_unenableColor(255, 128, 128, 128),
    m_nCheck( 0 )
  {
    m_uFirstPos = CONTROL_CHK_FIRST;
    m_uLastPos = CONTROL_CHK_LAST;
    SetAlignment( StringAlignmentNear );
    m_dwStyle = QS_CHK_OWNERDRAW;
    m_bunifyfont = FALSE;
  }

  /**
  *@method   ~CQsCheckBox
  *@brief       CQsCheckBox析構造函數
  *    
  *@return   
  */virtual ~CQsCheckBox()
  {

  }

  /**
  *@method   Create
  *@brief    通過Create來建立視窗
  *    
  *@param    HWND hWndParent  parent window
  *@param    ATL::_U_RECT rect    window rect
  *@param    LPCTSTR szWindowName  the window name
  *@param    DWORD dwStyle   base window style
  *@param    DWORD dwExStyle
  *@param    ATL::_U_MENUorID MenuOrID
  *@param    LPVOID lpCreateParam
  *@return   非NULL success return TRUE, failed return NULL
  */
  HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
    DWORD dwStyle = 0, DWORD dwExStyle = 0,
    ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
  {
    return theBaseClass::Create( hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
  }
  /**
  *@method   SetBtnUnifFont
  *@brief    設定CONTROL_CHK_CHECKED狀态下統一使用一種字型
  *    
  *@return   void
  */
  void SetBtnUnifFont(BOOL bunifyfont)
  {
    m_bunifyfont = bunifyfont;
  }
  /**
  *@method   SetAlignment
  *@brief    指定文本字元串相對于其布局矩形的對齊方式
  *    
  *@param    StringAlignment align  枚舉
            Center 指定文本在布局矩形中居中對齊。  
            Far 指定文本遠離布局矩形的原點位置對齊。在左到右布局中,遠端位置是右。在右到左布局中,遠端位置是左。  
            Near 指定文本靠近布局對齊。在左到右布局中,近端位置是左。在右到左布局中,近端位置是右 
  *@return   void
  */void SetAlignment( StringAlignment align )
  {
    m_eAlignment = align;
  }

  /**
  *@method   GetAlignment
  *@brief        得到定文本字元串相對于其布局矩形的對齊方式
  *    
  *@param    void
  *@return   StringAlignment 枚舉
            Center 指定文本在布局矩形中居中對齊。  
            Far 指定文本遠離布局矩形的原點位置對齊。在左到右布局中,遠端位置是右。在右到左布局中,遠端位置是左。  
            Near 指定文本靠近布局對齊。在左到右布局中,近端位置是左。在右到左布局中,近端位置是右 
  */
  StringAlignment GetAlignment( void )
  {
    return m_eAlignment;
  }
   /**
   *@method   SetQSWindowsStyle
   *@brief        設定視窗的樣式
   *    
   *@param    DWORD dwstyle dwstyle 視窗的樣式
   *@return   void
   */void SetQSWindowsStyle(DWORD dwstyle)
   {
      m_dwStyle = dwstyle;
   }
  /**
  *@method   SubclassWindow
  *@brief        類對象關聯
  *    
  *@param    HWND hWnd  對象句柄
  *@return   BOOL  成功傳回TRUE,失敗傳回FALSE
  */BOOL SubclassWindow( HWND hWnd )
  {
    //在此之前可能已經SetCheck
    m_nCheck = (int)::SendMessage( hWnd, BM_GETCHECK, 0, 0 );

    BOOL bRet = theBaseClass::SubclassWindow( hWnd );
    if(m_dwStyle&QS_CHK_OWNERDRAW)
    {
      UINT nBS = GetButtonStyle();
      SetButtonStyle( nBS | BS_OWNERDRAW );
    }
    return bRet;
  }
  /**
  *@method   GetState
  *@brief        得到CheckBox的現在的狀态
  *    
  *@param    void
  *@return   UINT  現在CheckBox的狀态
  */UINT GetState( void )
  {
    LONG lStyle = GetWindowLong( GWL_STYLE );
    BOOL bIsDisabled = ( ( lStyle & WS_DISABLED ) != 0 ); //是否被禁止
    BOOL bIsChecked = ( GetCheck() == BST_CHECKED );
    UINT uStateFont = CONTROL_BTN_NORMAL;
    BOOL bIsFocused = ( ::GetFocus() == m_hWnd );

    //如果目前處于失效狀态
    if( bIsDisabled )
    {
      if( bIsChecked)//如果目前被鈎選
      {
        
        uStateFont = CONTROL_CHK_DISCHECKED;
      }
      else
      {
        uStateFont = CONTROL_CHK_DISUNCHECK;
      }
    }
    else
    {
      if( bIsChecked )//如果目前被鈎選
      {
        if(bIsFocused)
        {
          uStateFont = CONTROL_CHK_FOUCS_CHECKED;
        }
        else
        {
          uStateFont = CONTROL_CHK_CHECKED;
        }
        
      }
      else
      {
        if(bIsFocused)
        {
          uStateFont = CONTROL_CHK_FOUCS_UNCHECK;
        }
        else
        {
          uStateFont = CONTROL_CHK_UNCHECK;
        }
      }
    }
    return uStateFont;
  }
  /**
  *@method   GetCheckStateFont
  *@brief        得到CheckBox的現在的狀态
  *    
  *@param    void
  *@return   UINT  現在CheckBox的狀态
  */UINT GetCheckStateFont( void )
  {
    LONG lStyle = GetWindowLong( GWL_STYLE );
    BOOL bIsDisabled = ( ( lStyle & WS_DISABLED ) != 0 ); //是否被禁止
    BOOL bIsChecked = ( GetCheck() == BST_CHECKED );
    UINT uStateFont = CONTROL_CHK_CHECKED;
    BOOL bIsFocused = ( ::GetFocus() == m_hWnd );

    if(m_bunifyfont == TRUE)
    {
      return  uStateFont;
    }
    //如果目前處于失效狀态
    if( bIsDisabled )
    {
      if( bIsChecked)//如果目前被鈎選
      {
        
        uStateFont = CONTROL_CHK_DISCHECKED;
      }
      else
      {
        uStateFont = CONTROL_CHK_DISUNCHECK;
      }
    }
    else
    {
      if( bIsChecked )//如果目前被鈎選
      {
        if(bIsFocused)
        {
          uStateFont = CONTROL_CHK_CHECKED;
        }
        else
        {
          uStateFont = CONTROL_CHK_CHECKED;
        }
        
      }
      else
      {
        if(bIsFocused)
        {
          uStateFont = CONTROL_CHK_UNCHECK;
        }
        else
        {
          uStateFont = CONTROL_CHK_UNCHECK;
        }
      }
    }
    return uStateFont;
  }
  /**
  *@method   GetTextFont
  *@brief        根據控件的狀态獲得控件目前使用的字型
  *    
  *@param    void
  *@return   HFONT  現在CheckBox的狀态字型對象
  */
  HFONT GetTextFont( void )
  {
    return GetStateFont( GetCheckStateFont() );
  }

  /**
  *@method   SetEnableColor
  *@brief        設定可用時字型的顔色
  *    
  *@param    Color enableColor  可用時字型的顔色
  *@return   void
  */
  void SetEnableColor(Color enableColor)
  {
    m_enableColor =  enableColor;
  }

  /**
  *@method   SetUnEnableColor
  *@brief        設定不可用時字型的顔色
  *    
  *@param    Color unenableColor 不可用時字型的顔色
  *@return   void
  */
  void SetUnEnableColor(Color unenableColor)
  {
    m_unenableColor = unenableColor;
  }
public:

  /**
  *@method   GetTextImageRect
  *@brief        得到字型和圖檔的顯示區域
  *    
  *@param    RECT * lpTextRect  字型所在的區域
  *@param    RECT * lpImageRect  圖檔所在的區域
  *@return   void
  */void GetTextImageRect( RECT* lpTextRect, RECT* lpImageRect )
  {
    CRect rtCtrl;
    GetClientRect( &rtCtrl );

    Image *pImg = GetCurrentImage(  );
    HFONT hFont = GetTextFont( );

    HDC hDC = ::GetDC( m_hWnd );
    Graphics graph( hDC );
    Gdiplus::Font fnt( hDC, hFont );
    
        RectF rtfText( 0, 0,(REAL)rtCtrl.Width(), (REAL)rtCtrl.Height() );

    RectF boundText( 0.0, 0.0, 0.0, 0.0 );
    TCHAR szTxt[TXTMAX] = {'0'};
    GetWindowText( szTxt, TXTMAX );
    StringFormat strfmtText;
    StringAlignment align = GetAlignment();
    strfmtText.SetAlignment( align );
      strfmtText.SetLineAlignment( StringAlignmentNear );
    if( szTxt[0] != 0 )
    {
      graph.MeasureString( szTxt, (int)_tcslen(szTxt),&fnt, rtfText, &strfmtText,&boundText );
    }

    int nImgWidth = 0;
    int nImgHeight = 0;
    if ( pImg != NULL )
    {
      nImgWidth = pImg->GetWidth();
      nImgHeight = pImg->GetHeight();
    }
    if( StringAlignmentFar == GetAlignment() )
    {
      lpTextRect->left = (LONG)(rtCtrl.Width() - boundText.Width);
      lpTextRect->top = 0;
      lpTextRect->right = rtCtrl.Width();
      lpTextRect->bottom = rtCtrl.Height();
      int ytmp = rtCtrl.Height() - nImgHeight;
      lpImageRect->left = lpTextRect->left - nImgWidth - 5 ;
      lpImageRect->top = ( ytmp < 0 ? 0 : ytmp ) / 2;
      lpImageRect->right = lpImageRect->left + nImgWidth;
      lpImageRect->bottom = lpImageRect->top + nImgHeight;
    }
    else if( StringAlignmentCenter == GetAlignment() )
    {
      int nTotalWidth = (int)(nImgWidth + 10 + boundText.Width);
      int nLeft = ( rtCtrl.Width() - nTotalWidth ) / 2;
      nLeft = nLeft < 0 ? 0: nLeft;
      
      int ytmp = rtCtrl.Height() - nImgHeight;
      lpImageRect->left = nLeft;
      lpImageRect->top = ( ytmp < 0 ? 0 : ytmp ) / 2;
      lpImageRect->right = lpImageRect->left + nImgWidth;
      lpImageRect->bottom = lpImageRect->top + nImgHeight;
      lpTextRect->left = lpImageRect->right + 5;
      lpTextRect->top = 0;
      lpTextRect->right = (LONG)(lpTextRect->left + boundText.Width + 2);
      lpTextRect->bottom = rtCtrl.Height();
    }
    else
    {
      int ytmp = (int)(rtCtrl.Height() - nImgHeight);
      lpImageRect->left = 0;
      lpImageRect->top = ( ytmp < 0 ? 0 : ytmp ) / 2;
      lpImageRect->right = lpImageRect->left + nImgWidth;
      lpImageRect->bottom = lpImageRect->top + nImgHeight;
      lpTextRect->left = lpImageRect->right + 5;
      lpTextRect->top = 0;
      lpTextRect->right = (LONG)rtCtrl.right;//(LONG)(lpTextRect->left + boundText.Width+2);
      lpTextRect->bottom = rtCtrl.Height();
    }
    graph.ReleaseHDC( hDC );
    ReleaseDC( hDC );
    DeleteObject( hFont );
  }

  /**
  *@method   DrawItem
  *@brief       按鈕重畫函數
  *    
  *@param    LPDRAWITEMSTRUCT lpdis
  *@return   void
  */void DrawItem( LPDRAWITEMSTRUCT lpdis )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return ;
    }
    int width = lpdis->rcItem.right - lpdis->rcItem.left;
    int height = lpdis->rcItem.bottom - lpdis->rcItem.top;

    //建立記憶體作圖對象
    WTL::CDC memDC;
    memDC.CreateCompatibleDC( lpdis->hDC );
    WTL::CBitmap memBitmap;
    memBitmap.CreateCompatibleBitmap( lpdis->hDC, width, height );
    HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap );

    //獲得控件背景
    memDC.SetBkMode( TRANSPARENT );
    ::SendMessage( GetParent(), WM_DRAWBKGNDUI, ( WPARAM )memDC.m_hDC, ( LPARAM )lpdis->hwndItem );

    //繪制按鈕
    DrawButton( memDC.m_hDC, lpdis->rcItem );

    //送出圖像
    ::BitBlt( lpdis->hDC, 0, 0, width, height, memDC.m_hDC, 0, 0, SRCCOPY );

    memDC.SelectBitmap( hOldBmp );
    memBitmap.DeleteObject();
    memDC.DeleteDC();
  }
protected:

  /**
  *@method   OnSetCheck
  *@brief    設定狀态消息響應函數
  *    
  *@param    UINT uMsg   消息類型
  *@param    WPARAM wParam   詳見MSDN
  *@param    LPARAM lParam   詳見MSDN
  *@param    BOOL &
  *@return   LRESULT
  */LRESULT OnSetCheck( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return DefWindowProc(uMsg, wParam, lParam);
    }
    switch( wParam )
    {
    case BST_CHECKED:
    case BST_INDETERMINATE:
      m_nCheck = BST_CHECKED;
      break;
    default:
      m_nCheck = BST_UNCHECKED;
      break;
    }
    Invalidate();
    //OutputDebugStr( _T("OnSetCheck\r\n") );
    return 0;
  }

  /**
  *@method   OnGetCheck
  *@brief    讀取狀态消息響應函數
  *    
  *@param    UINT uMsg   消息類型
  *@param    WPARAM wParam  詳見MSDN
  *@param    LPARAM lParam  詳見MSDN
  *@param    BOOL &
  *@return   LRESULT   詳見MSDN
  */LRESULT OnGetCheck( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return DefWindowProc(uMsg, wParam, lParam);
    }
    return m_nCheck;
  }

  /**
  *@method   OnLButtonDown
  *@brief    滑鼠左鍵被按下消息響應函數
  *    
  *@param    UINT uMsg 消息類型
  *@param    WPARAM wParam 未被使用
  *@param    LPARAM lParam 詳見MSDN
  *@param    BOOL& bHandled 未被使用
  *@return   LRESULT 詳見MSDN
  */
  LRESULT OnLButtonDown( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
  {
    //OutputDebugStr( _T("OnLButtonDown\r\n") );
    m_bMouseDown = true;
    //Invalidate();
    bHandled = FALSE;
    return 0;
  }

  /**
  *@method   OnMouseMove
  *@brief    滑鼠進入消息響應函數
  *    
  *@param    UINT uMsg    消息類型
  *@param    WPARAM wParam    未被使用
  *@param    LPARAM lParam    詳見MSDN
  *@param    BOOL& bHandled   未被使用
  *@return   LRESULT
  */
  LRESULT OnMouseMove( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return TRUE;
    }
    if( m_pCurImage != GetImage( CONTROL_BTN_MOUSEIN ) )
    {
      //Invalidate();

      // 啟動滑鼠離開時間
      TRACKMOUSEEVENT tme;
      tme.cbSize  = sizeof(tme);
      tme.hwndTrack = m_hWnd;
      tme.dwFlags = TME_LEAVE;
      TrackMouseEvent(&tme);
    }

    bHandled = FALSE;
    return 0;
  }

  /**
  *@method   OnMouseLeave
  *@brief    滑鼠離開消息響應函數
  *    
  *@param    UINT uMsg    消息類型
  *@param    WPARAM wParam    未被使用
  *@param    LPARAM lParam    詳見MSDN
  *@param    BOOL& bHandled   未被使用
  *@return   LRESULT  詳見MSDN
  */
  LRESULT OnMouseLeave( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return TRUE;
    }
    //Invalidate();
    bHandled = FALSE;
    return 0;
  }

  /**
  *@method   OnLButtonUp
  *@brief    滑鼠左鍵被放開消息響應函數
  *    
  *@param    UINT uMsg    消息類型
  *@param    WPARAM wParam    未被使用
  *@param    LPARAM lParam    詳見MSDN
  *@param    BOOL& bHandled   未被使用
  *@return   LRESULT  詳見MSDN
  */
  LRESULT OnLButtonUp( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL/*& bHandled*/ )
  {
    //OutputDebugStr( _T("OnLButtonUp\r\n") );
    m_bMouseDown = false;
    SendMessage(WM_KILLFOCUS,0,0);
     int nCtrlID = GetDlgCtrlID( );
     SetCheck( !GetCheck() );
     Invalidate();
    ::SendMessage( GetParent(), WM_COMMAND, (WPARAM)nCtrlID,LPARAM(m_hWnd));
    
    //bHandled = FALSE;
    return 0;
  }

  /**
  *@method   OnEraseBKGnd
  *@brief    背景繪制消息函數
  *    
  *@param    UINT uMsg    消息類型
  *@param    WPARAM wParam    未被使用
  *@param    LPARAM lParam    詳見MSDN
  *@param    BOOL& bHandled   未被使用
  *@return   LRESULT  詳見MSDN
  */
  LRESULT OnEraseBKGnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return DefWindowProc(uMsg, wParam, lParam);
    }
    return 0;
  }

  /**
  *@method   OnClicked
  *@brief    按鈕被按下消息響應函數
  *    
  *@param    WORD wNotifyCode 通知消息代碼
  *@param    WORD wID 發送該消息的控件ID
  *@param    HWND hWndCtl 發送該消息的控件的句柄
  *@param    BOOL& bHandled   消息是否繼續處理标志
  *@return   LRESULT
  */
  LRESULT OnClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  {
    if(m_dwStyle&QS_CHK_SYSYSTEM)
    {
      return 0;
    }
    //OutputDebugStr( _T("OnClicked\r\n") );
    SetCheck( !GetCheck() );

    Invalidate();
    return 0;
  }

private:
  /**
  *@method   GetButtonTextFormat
  *@brief    得到Button文字的對齊方式(用DrawText()輸出時的格式)
  *    
  *@param    const LONG lStyle    控件風格  
  *@return   UINT 用DrawText()輸出時的格式    button上的字必須是一行   
  */
  UINT GetButtonTextFormat(const LONG lStyle)
  {
    UINT uFormat = DT_SINGLELINE;     //button上的字必須是一行
    
    //x方向
    if ( (lStyle & BS_CENTER)==BS_CENTER )//x方向,中
      uFormat |= DT_CENTER;
    else if ( (lStyle & BS_RIGHT)==BS_RIGHT )//x方向,右
      uFormat |= DT_RIGHT;
    else if ( (lStyle & BS_LEFT) == BS_LEFT )//x方向,左
      uFormat |= DT_LEFT;
    else//預設,x中
      uFormat |= DT_LEFT;
    
    //y方向
    if ( (lStyle & BS_VCENTER ) == BS_VCENTER )//y,中
      uFormat |= DT_VCENTER;
    else if ( (lStyle & BS_TOP)==BS_TOP )//y方向,上
      uFormat |= DT_TOP;
    else if ( (lStyle & BS_BOTTOM)==BS_BOTTOM )//y方向,下
      uFormat |= DT_BOTTOM;
    else//預設,y中
      uFormat |= DT_VCENTER;
    
    return uFormat;
  }

  /**
  *@method   GetCurrentImage
  *@brief    得到目前CheckBox使用的圖檔
  *    
  *@param    void
  *@return   Image*  目前圖檔的的對象指針
  */Image* GetCurrentImage( void )
  {
    Image *pImg = NULL;
    UINT uStateFont = GetState();

    pImg = GetImage( uStateFont );

    //如果沒有對應狀态的圖檔
    if( pImg == NULL )
    {
      if( m_pCurImage != NULL )
      {
        pImg = m_pCurImage;
      }
      else
      {
        pImg = GetImage( CONTROL_BTN_NORMAL );
      }
    }
    return pImg;
  }

  /**
  *@method   DrawButton
  *@brief    繪制按鈕函數
  *    
  *@param    HDC hDC   DC句柄
  *@param    RECT  itemRect 按鈕位置
  *@return   void
  */void DrawButton( HDC hDC, RECT /*itemRect*/ )
  {
    HDC hdc = hDC;

    SetBkMode( hdc, TRANSPARENT );
    
    LONG lStyle = GetWindowLong( GWL_STYLE );
    BOOL bIsDisabled = ( ( lStyle & WS_DISABLED ) != 0 ); //是否被禁止

    //判斷滑鼠是否在按鈕上
    CRect rc;
    GetWindowRect( rc );
    
    POINT pt;
    GetCursorPos( &pt );

    Image *pImg = GetCurrentImage( );

    //如果目前圖檔相同
    if( m_pCurImage != pImg )
    {
      //儲存上一個狀态的圖檔
      if( m_pCurImage != NULL)
      {
        m_pLastImage = m_pCurImage;
      }
      else
      {
        m_pLastImage = pImg;
      }
      m_pCurImage = pImg;
    }

    CRect rtImage, rtText;
    GetTextImageRect( rtText, rtImage );

    if( m_pCurImage != NULL )
    {
      //繪制圖檔
      Graphics graph( hDC );
      graph.SetPageScale( 1.0 );
      graph.SetPageUnit( UnitPixel ); 
      graph.SetSmoothingMode( SmoothingModeNone );
      graph.DrawImage( m_pCurImage, rtImage.left, rtImage.top, rtImage.Width(), rtImage.Height() );
      graph.ReleaseHDC( hDC );
    }

    //繪制文字
    TCHAR szTxt[TXTMAX] = {0};
    GetWindowText( szTxt, TXTMAX );

    //獲得控件目前使用的字型
    HFONT hFont = GetTextFont(  );

    WTL::CDCHandle dc( hDC );

    Graphics graph(dc.m_hDC);
    Gdiplus::Font fnt( dc.m_hDC, hFont );

    StringFormat strfmt;
    strfmt.SetAlignment(StringAlignmentCenter);
    strfmt.SetLineAlignment(StringAlignmentCenter);
    CRect rtf( rtText.left,rtText.top,rtText.right,rtText.Height()); 
    if( bIsDisabled )
    {
      //SolidBrush sdb(m_unenableColor);
      //graph.DrawString( szTxt,(int)_tcslen(szTxt), &fnt, rtf,&strfmt,  &sdb );  
      HFONT hOldFont = dc.SelectFont( hFont );
      dc.SetTextColor(m_unenableColor.ToCOLORREF());
      dc.DrawText( szTxt, -1, &rtf, GetButtonTextFormat( lStyle ) );
      dc.SelectFont( hOldFont );
      //SolidBrush sdb(m_unenableColor);
      //graph.DrawString( szTxt,(int)_tcslen(szTxt), &fnt, rtf,&strfmt,  &sdb );
    }
    else
    {
      HFONT hOldFont = dc.SelectFont( hFont );
      dc.SetTextColor(m_enableColor.ToCOLORREF());
      dc.DrawText( szTxt, -1, &rtf, GetButtonTextFormat( lStyle ) );
      dc.SelectFont( hOldFont );

      //SolidBrush sdb(m_enableColor); //可用狀态時字型的顔色
      //graph.DrawString( szTxt,(int)_tcslen(szTxt),&fnt, rtf,&strfmt,&sdb );
    }
    graph.ReleaseHDC(dc.m_hDC);
    DeleteObject( hFont );
  }
};