天天看点

WTL 窗口自绘 (CQsSkinWindowUI)

概述:

代码实现如下:

#pragma once
#include "UserMessage.h"
#include "QsCtrls.h"
#include <vector>
#include "ResourceManager.h"

#pragma comment(lib, "ResourceManager.lib")

template< class T, bool _bIsChildWnd = false >
class CQsSkinWindowUI//: public CQsMaxMinBase<T>
{
public:
    typedef enum
    {
        WINUI_FIRST = 0,
        WINUI_TOPLEFT,     //窗口左上角
        WINUI_TOP,         //窗口顶部
        WINUI_TOPRIGHT,    //窗口右上角
        WINUI_CENTERLEFT,  //窗口中部左边
        WINUI_CENTER,      //窗口中部
        WINUI_CENTERRIGHT, //窗口中部右边
        WINUI_BOTTOMLEFT,  //窗口底部左边
        WINUI_BOTTOM,      //窗口底部
        WINUI_BOTTOMRIGHT, //窗口底部右边
        WINUI_LAST
    };
//typedef CQsMaxMinBase<T> theMaxMinClass;
private:
    CRect  m_rcWnd;                             //当前画刷图像尺寸
    Image  *m_pImage[WINUI_LAST];    //窗口背景分解图
protected:
    Bitmap *m_pBKImage;                    //当前窗口背景图片

    bool m_bIsTransparent;                  //  窗口是否透明

public:
    BEGIN_MSG_MAP(CQsSkinWindowUI)
        MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
        MESSAGE_HANDLER( WM_DRAWBKGNDUI, OnDrawBKGndUI )
        MESSAGE_HANDLER( WM_DRAWBKGNDUIEX, OnDrawBKGndUIEx )
        MESSAGE_HANDLER( WM_SIZE, OnSize )
        MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBkgnd )
        MESSAGE_HANDLER(WM_REDRAWBKGND, OnRedrawBkgnd )
        //CHAIN_MSG_MAP(theMaxMinClass)
    END_MSG_MAP()

    DECLARE_WND_CLASS( _T("QsSkinWindow") )

    /**
    *@method   CQsSkinWindowUI
    *@brief    CQsSkinWindowUI类构造函数
    *    
    *@return   
    */
    CQsSkinWindowUI():
        m_pBKImage( NULL )
    {
        for( int i = WINUI_FIRST; i < WINUI_LAST; i++ )
        {
            m_pImage[i] = NULL;
        }
        m_bIsTransparent = false;
    }

    /**
    *@method   ~CQsSkinWindowUI
    *@brief    CQsSkinWindowUI析构造函数
    *    
    *@return   
    */
    virtual ~CQsSkinWindowUI()
    {
        //释放图片资源
        for( int i = WINUI_FIRST; i < WINUI_LAST; i++ )
        {
            delete m_pImage[i];
        }

        //释放当前窗口背景图片
        if( m_pBKImage )
        {
            delete m_pBKImage;
            m_pBKImage = NULL;
        }

        //释放按钮控件
        int nSize = m_ctlButtons.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsButton *p = m_ctlButtons[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlButtons.RemoveAll();

        //释放CheckBox
        nSize = m_ctlCheckBoxs.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsCheckBox *p = m_ctlCheckBoxs[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlCheckBoxs.RemoveAll();

        //释放RadioBoxs
        nSize = m_ctlRadioBoxs.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsRadioBox *p = m_ctlRadioBoxs[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlRadioBoxs.RemoveAll();

        //释放ComboBox
        nSize = m_ctlComboBoxs.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsComboBox *p = m_ctlComboBoxs[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlComboBoxs.RemoveAll();

        //释放Edit
        nSize = m_ctlEdits.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsEdit *p = m_ctlEdits[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlEdits.RemoveAll();

        //释放Edit
        nSize = m_ctlProgs.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQSProgressBar *p = m_ctlProgs[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlProgs.RemoveAll();


        //释放CCustomStatic2
        nSize = m_ctlStaCtrls.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            CQsStatic *p = m_ctlStaCtrls[i];
            ATLASSERT( p );
            delete p;
        }
        m_ctlStaCtrls.RemoveAll();

        //释放控件状态图片对象
        nSize = m_stImages.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            STATEIMAGE *p = m_stImages[i];
            delete p;
        }
        m_stImages.RemoveAll();
    }

    /**
    *@method   SetExSkin
    *@brief    换肤时消息背景图片删除和公共控件图片的加载
    *    
    *@return   void
    */
    void SetExSkin()
    {
        for( int i = WINUI_FIRST; i < WINUI_LAST; i++ ) //bei背景先清除掉
        {
            delete m_pImage[i];
        }
        //释放当前窗口背景图片
        if( m_pBKImage )
        {
            delete m_pBKImage;
            m_pBKImage = NULL;
        }
        SubClassImagePublic();
    }

    /**
    *@method    SetTransparent
    *@brief     设置窗口是否透明
    *    
    *@param     bool bTrans
    *@return    void
    */
    void SetTransparent( bool bTrans = true )
    {
        m_bIsTransparent = bTrans;
    }

    /**
    *@method   OnInitDialog
    *@brief    对话框窗口初始化消息响应函数
    *    
    *@param    UINT uMsg        消息类型
    *@param    WPARAM wParam    未被使用
    *@param    LPARAM lParam    详见MSDN
    *@param    BOOL& bHandled   未被使用
    *@return   LRESULT
    */
    LRESULT OnInitDialog( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
    {
        T *pT = static_cast< T* >( this );
        HMENU  hSystemMenu = ::GetSystemMenu( pT->m_hWnd, FALSE );

        if ( NULL != hSystemMenu )
        {
            ::RemoveMenu( hSystemMenu, SC_MOVE, MF_BYCOMMAND );
        }
        //ShowMenuButton();
        return 0;
    }

protected:

    /**
    *@method   OnSysCommand
    *@brief    对话框窗口尺寸发生变化消息响应函数
    *    
    *@param    UINT uMsg       消息类型
    *@param    WPARAM wParam   未被使用
    *@param    LPARAM lParam   详见MSDN
    *@param    BOOL& bHandled  未被使用
    *@return   LRESULT
    */
    LRESULT OnSysCommand( UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
    {
        bHandled = FALSE;

        return TRUE;
    }

    /**
    *@method   OnSize
    *@brief    对话框窗口尺寸发生变化消息响应函数
    *    
    *@param    UINT  uMsg     消息类型
    *@param    WPARAM wParam  未被使用
    *@param    LPARAM lParam  详见MSDN
    *@param    BOOL& bHandled 未被使用
    *@return   LRESULT
    */
    LRESULT OnSize( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled )
    {
        T *pT = static_cast< T* >( this );
        int cx = LOWORD( lParam );
        int cy = HIWORD( lParam );

        //重新生成背景图片
        if( !CreateBKImageEx( cx, cy ) )
        {
            return 0;
        }
        CRect rect;
        pT->GetClientRect(&rect);
        pT->InvalidateRect( rect );
        bHandled = false;
        return 0;
    }
    
    /**
    *@method   SubQSclassAllControls
    *@brief     将窗口上的所有控件进行关联
    *    
    *@param    void
    *@return   BOOL
    */
    virtual BOOL SubQSclassAllControls( void )
    {
        SubClassImagePublic();

        SetPublicDefaultFont();

        SetPublicDefaultColor();

        return SubclassAllControls();
    }

    /**
    *@method   SetPublicDefaultColor
    *@brief    设置默认字体的颜色
    *    
    *@return   void
    */
    void SetPublicDefaultColor()
    {
        DWORD dword =0;
        std::wstring sss = _T("default_color");
        GetColor(sss,dword);

        CCtrlImageMgr::SetDefaultFontColor(dword);
    }

    /**
    *@method   SetPublicDefaultFont
    *@brief    设置窗口默认的字体
    *    
    *@return   void
    */
    void SetPublicDefaultFont()
    {
        std::wstring strfontName;
        double nfontsize=0;
        int nfontstyle =0;
        int fnWeight = FW_NORMAL; 
        BYTE bItalic = FALSE;
        BYTE bUnderline = FALSE; 
        BYTE bStrikeOut = FALSE;

        GetFontEx(_T("default_font"),strfontName,nfontsize,nfontstyle);

        if(FontStyleRegular == nfontstyle)
        {
            fnWeight = FW_NORMAL;
        }
        else if(FontStyleBold == nfontstyle)
        {
            fnWeight = FW_BOLD;
        }
        else if(FontStyleItalic == nfontstyle)
        {
            bItalic = TRUE;
        }
        else if(FontStyleBoldItalic == nfontstyle)
        {
            bItalic = TRUE;
            fnWeight = FW_BOLD;
        }
        else if(FontStyleUnderline == nfontstyle)
        {
            bUnderline = TRUE;
        }
        else if(FontStyleStrikeout == nfontstyle)
        {
            bStrikeOut = TRUE;
        }
        CCtrlImageMgr::SetDefaultFont(strfontName.c_str(),(int)nfontsize,fnWeight,bItalic,bUnderline,bStrikeOut);
    }

    /**
    *@method   SubClassImagePublic
    *@brief    设置公共控件的Image
    *    
    *@return   void
    */
    void SubClassImagePublic()
    {
        CCtrlImageMgr::ClearStateImage();
        按钮
        Image *pImg = NULL;
        GetImage( _T("comm_button.png"), pImg);

        if(NULL != pImg)
        {
            CCtrlImageMgr::SetStateImage( CONTROL_BTN_NORMAL, pImg, 0, 0, 84, 37 );
            CCtrlImageMgr::SetStateImage( CONTROL_BTN_FOCUS, pImg, 84, 0, 84, 37 );
            CCtrlImageMgr::SetStateImage( CONTROL_BTN_MOUSEIN, pImg, 84, 0, 84, 37 );
            CCtrlImageMgr::SetStateImage( CONTROL_BTN_MOUSEDOWN, pImg, 168, 0, 84, 37 );
            CCtrlImageMgr::SetStateImage( CONTROL_BTN_DISABLED, pImg, 252, 0, 84, 37 );
        }

        //复选框
        GetImage( _T("comm_checkbox.png"), pImg);
        if(NULL != pImg)
        {   
            CCtrlImageMgr::SetStateImage( CONTROL_CHK_DISCHECKED, pImg,0,0,18,18 );
            CCtrlImageMgr::SetStateImage( CONTROL_CHK_CHECKED, pImg,18,0,18,18);
            CCtrlImageMgr::SetStateImage( CONTROL_CHK_DISUNCHECK, pImg,36,0,18,18 );
            CCtrlImageMgr::SetStateImage( CONTROL_CHK_UNCHECK, pImg,54,0,18,18);
            GetImage( _T("comm_checkbox_select_focus.png"), pImg);
            if(NULL!= pImg)
            {
                CCtrlImageMgr::SetStateImage( CONTROL_CHK_FOUCS_CHECKED, pImg,0,0,18,18);
            }
            GetImage( _T("comm_checkbox_unselect_focus.png"), pImg);
            if(NULL!= pImg)
            {
                CCtrlImageMgr::SetStateImage( CONTROL_CHK_FOUCS_UNCHECK, pImg,0,0,18,18);
            }
        }
        //单选框
        GetImage( _T("comm_radiobox.png"), pImg);
        if(NULL != pImg)
        {

            CCtrlImageMgr::SetStateImage( CONTROL_RDB_UNCHECK, pImg, 0, 0, 20, 20 );
            CCtrlImageMgr::SetStateImage( CONTROL_RDB_CHECKED, pImg, 20, 0, 20, 20 );
            CCtrlImageMgr::SetStateImage( CONTROL_RDB_DISUNCHECK, pImg, 40, 0, 20, 20 );
            CCtrlImageMgr::SetStateImage( CONTROL_RDB_DISCHECKED, pImg, 60, 0, 20, 20 );


        }
        GetImage( _T("comm_combox.png"), pImg);
        if(NULL != pImg)
        {

            CCtrlImageMgr::SetStateImage( CONTROL_CBS_NORMAL, pImg, 0, 0, 24, 24 );
            CCtrlImageMgr::SetStateImage( CONTROL_CBS_FOCUS, pImg, 0, 0, 24, 24 );
            CCtrlImageMgr::SetStateImage( CONTROL_CBS_MOUSEIN, pImg, 24, 0, 24, 24 );
            CCtrlImageMgr::SetStateImage( CONTROL_CBS_MOUSEDOWN, pImg, 48, 0, 24, 24 );
            CCtrlImageMgr::SetStateImage( CONTROL_CBS_DISABLED, pImg, 72, 0, 24, 24 );
        }
    }
    
    /**
    *@method   OnEraseBkgnd
    *@brief    窗口背景绘制消息
    *    
    *@param    UINT uMsg        消息类型
    *@param    WPARAM wParam    未被使用
    *@param    LPARAM lParam    详见MSDN
    *@param    BOOL&  bHandled  未被使用
    *@return   LRESULT
    */
    LRESULT OnEraseBkgnd( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
    {
        return FALSE;
    }

    LRESULT OnRedrawBkgnd( UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ )
    {
        ReDraw();
        return TRUE;
    }


    /**
    *@method   OnCtlColorStatic
    *@brief    窗口绘制消息响应函数
    *    
    *@param    UINT uMsg       消息类型
    *@param    WPARAM wParam   未被使用
    *@param    LPARAM lParam   详见MSDN
    *@param    BOOL& bHandled  未被使用
    *@return   LRESULT
    */
    LRESULT OnCtlColorStatic( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
    {
        T *pT = static_cast< T* >( this );
        HWND hwnd = ( HWND )lParam;
        for( int i = 0; i < m_ctlStaCtrls.GetSize(); i++ )
        {
            if( m_ctlStaCtrls[i]->m_hWnd == hwnd )
            {

                HDC hdc = ( HDC )wParam;

                //用控件背景做一个画刷
                WTL::CDC memDC;
                memDC.CreateCompatibleDC( hdc );
                WTL::CBitmap memBitmap;
                CRect rc;
                ::GetWindowRect( hwnd, rc );
                memBitmap.CreateCompatibleBitmap( hdc, rc.Width(), rc.Height() );
                HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap.m_hBitmap );

                //获得控件背景
                pT->SendMessage( WM_DRAWBKGNDUI, ( WPARAM )memDC.m_hDC, ( LPARAM )hwnd );

                //创建画刷
                HBRUSH hBrush = ::CreatePatternBrush( memBitmap.m_hBitmap );

                memDC.SelectBitmap( hOldBmp );

                return ( LRESULT )hBrush;//( LRESULT )::GetStockObject( NULL_BRUSH );
            }
        }

        return DefWindowProc( pT->m_hWnd, uMsg, wParam, lParam );

    }
    
    /**
    *@method   OnDrawBKGndUI
    *@brief    绘制子控件背景
    *    
    *@param    UINT uMsg        消息类型
    *@param    WPARAM wParam    未被使用
    *@param    LPARAM lParam    详见MSDN
    *@param    BOOL& bHandled   未被使用
    *@return   LRESULT
    */
    LRESULT OnDrawBKGndUI( UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        HDC hdc = ( HDC )wParam;
        HWND hwnd = ( HWND )lParam;

        //获得当前控件在窗口上的位置
        T *pT = static_cast< T* >( this );

        if( !m_pBKImage )
        {
            CRect rc;
            pT->GetWindowRect( rc );

            if( !CreateBKImageEx( rc.Width(), rc.Height() ) )
                return FALSE;
        }

        //获得控件在当前窗口上的位置
        CRect rc;
        ::GetWindowRect( hwnd, rc );
        pT->ScreenToClient( rc );

        //将图像复制给控件
        Graphics graph( hdc );
        graph.DrawImage( m_pBKImage, Rect( 0, 0, rc.Width(), rc.Height() ),
            rc.left, rc.top, rc.Width(), rc.Height(), UnitPixel );
        graph.ReleaseHDC( hdc );

        return 0;
    }

    LRESULT OnDrawBKGndUIEx( UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        Graphics* pGraph = (Graphics*)wParam;
        HWND hwnd = ( HWND )lParam;

        //获得当前控件在窗口上的位置
        T *pT = static_cast< T* >( this );

        if( !m_pBKImage )
        {
            CRect rc;
            pT->GetWindowRect( rc );

            if( !CreateBKImageEx( rc.Width(), rc.Height() ) )
                return FALSE;
        }

        //获得控件在当前窗口上的位置
        CRect rc;
        ::GetWindowRect( hwnd, rc );
        pT->ScreenToClient( rc );

        pGraph->DrawImage( m_pBKImage, Rect( 0, 0, rc.Width(), rc.Height() ),
            rc.left, rc.top, rc.Width(), rc.Height(), UnitPixel );

        return TRUE;
    }

    /**
    *@method   OnPaint
    *@brief    窗口绘制消息响应函数
    *    
    *@param    UINT uMsg        消息类型
    *@param    WPARAM wParam    未被使用
    *@param    LPARAM lParam    详见MSDN
    *@param    BOOL& bHandled   未被使用
    *@return   LRESULT
    */
    LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        T *pT = static_cast< T* >( this );
        CRect rc;
        pT->GetWindowRect( rc );

        WTL::CPaintDC paintDC( pT->m_hWnd );

        //创建窗口图片对象
        WTL::CDC memDC;
        memDC.CreateCompatibleDC( paintDC.m_hDC );
        WTL::CBitmap memBitmap;
        memBitmap.CreateCompatibleBitmap( paintDC.m_hDC, rc.Width(), rc.Height() );
        HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap.m_hBitmap );

        BOOL bRet = CreateBkImage( memDC.m_hDC, rc.Width(), rc.Height() );
        if( bRet )
        {
            paintDC.StretchBlt( 0, 0, rc.Width(), rc.Height(), memDC.m_hDC, 0, 0, rc.Width(), rc.Height(), SRCCOPY );
        }
        memDC.SelectBitmap( hOldBmp );


        if( !bRet )
        {
#ifdef _USERLOGFILE
                _DEBUG_MSG( _LOGSTR( "创建窗口背景图片失败! cx=%d cy=%d" ), rc.Width(), rc.Height() );
#endif
            return ::DefWindowProc( pT->m_hWnd, uMsg, wParam, lParam );
        }

        return 0;
    }

    /**
    *@method   OnCtlColorDlg
    *@brief    获得对话框窗口背景
    *    
    *@param    UINT uMsg       消息类型
    *@param    WPARAM wParam   未被使用
    *@param    LPARAM lParam   详见MSDN
    *@param    BOOL& bHandled  未被使用
    *@return   LRESULT
    */
    LRESULT OnCtlColorDlg( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        T *pT = static_cast< T* >( this );
        CRect rc;
        pT->GetWindowRect( rc );
        HBRUSH hBrush = CreateBkBrush( rc.Width(), rc.Height() );
        if( !hBrush )
        {
            return ::DefWindowProc( pT->m_hWnd, uMsg, wParam, lParam );
        }

        return ( LRESULT ) hBrush;
    }

    /**
    *@method   CreateBkImage
    *@brief    创建背景图像
    *    
    *@param    HDC hDC
    *@param    int width  宽度
    *@param    int height 高度
    *@return   BOOL
    */
    BOOL CreateBkImage( HDC hDC, int width, int height )
    {
        CSize szBmp( 0, 0 ), szWnd( width, height );
        if( m_pBKImage )
        {
            szBmp = CSize( m_pBKImage->GetWidth(), m_pBKImage->GetHeight() );
        }

        if( szBmp != szWnd )
        {
            if( !CreateBKImageEx( width, height ) )
            {
#ifdef _USERLOGFILE
                _DEBUG_MSG( _LOGSTR( "创建窗口背景图片失败! cx=%d cy=%d" ), width, height );
#endif
                return FALSE;
            }
        }

        //将图像送给指定设备
        Graphics graph( hDC );
        graph.DrawImage( m_pBKImage, Rect( 0, 0, width, height ), 0, 0, width, height, UnitPixel );
        graph.ReleaseHDC( hDC );

        return TRUE;

    }

    /**
    *@method   CreateBkBrush
    *@brief    创建背景画刷
    *    
    *@param    int width  窗口宽度
    *@param    int height 窗口高度
    *@return   HBRUSH   成功返回创建的画刷句柄,否则返回NULL
    */
    HBRUSH CreateBkBrush( int width, int height )
    {
        WTL::CDC memDC;
        T *pT = static_cast< T* >( this );
        HDC hdc = pT->GetDC();

        //创建内存作图句柄
        memDC.CreateCompatibleDC( hdc );
        WTL::CBitmap memBitmap;
        memBitmap.CreateCompatibleBitmap( hdc, width, height );
        HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap.m_hBitmap );
        //创建背景
        BOOL bRet = CreateBkImage( memDC.m_hDC, width, height );
        memDC.SelectBitmap( hOldBmp );

        if( !bRet )
            return NULL;

        return CreatePatternBrush( memBitmap.m_hBitmap );
    }

private:

    /**
    *@method   CreateBKImageEx
    *@brief    创建当前背景图片
    *    
    *@param    int width  窗口宽度
    *@param    int height 窗口高度
    *@return   BOOL
    */
    BOOL CreateBKImageEx( int width, int height )
    {
        T *pT = static_cast< T* >( this );

        delete m_pBKImage;
        m_pBKImage = new Bitmap( width, height );
        if( NULL == m_pBKImage )
        {
#ifdef _USERLOGFILE
            _DEBUG_MSG( _LOGSTR( "创建窗口背景图片失败! cx=%d cy=%d" ), width, height );
#endif
            return FALSE;
        }
        Graphics gh( m_pBKImage );
        gh.SetPageScale( 1.0 );
        gh.SetPageUnit( UnitPixel ); 
        gh.SetSmoothingMode( SmoothingModeNone );

        //  如果是透明窗口,需要向父窗口发送请求,绘制父窗口在该位置的别经
        if ( m_bIsTransparent ) 
        {
            HWND hParent = pT->GetParent( );
            if ( NULL != hParent )
            {
                ::SendMessage( hParent, WM_DRAWBKGNDUIEX, (WPARAM)(&gh), ( LPARAM )pT->m_hWnd );
            }
        }
        else
        {
            //填充白色背景
            SolidBrush sb( Color( 255, 255, 255, 255 ) );
            gh.FillRectangle( &sb, 0, 0, width, height );
        }

        //调用背景绘制函数
        BOOL bRet =  OnDrawBKGnd( gh );
        if( !bRet )
        {
#ifdef _USERLOGFILE
            _DEBUG_MSG( _LOGSTR( "调用OnDrawBKGnd函数返回错误!" ) );
#endif
            delete m_pBKImage;
            m_pBKImage = NULL;
        }

//      if( !_bIsChildWnd )
//      {
//          //创建异形窗口
//          HRGN rgn = ::CreateRoundRectRgn( 3, 0, width-3, height-3, 10, 10 );
//          T *pT = static_cast< T* >( this );
//          ::SetWindowRgn( pT->m_hWnd, rgn, TRUE );
//          DeleteObject( rgn );
//      }

        return bRet;

    }

    /**
    *@method   CheckBKImage
    *@brief    检查窗口背景分解图的完整性
    *    
    *@param    void
    *@return   BOOL
    */
    BOOL CheckBKImage( void )
    {
        for( int i = 1; i < 10; i++ )
        {
            if( m_pImage[i] == NULL )
                return FALSE;
        }

        return TRUE;
    }
    

public:
    
    /**
    *@method   ResizeWindow
    *@brief    重新绘制窗口背景
    *    
    *@param    void
    *@return   BOOL
    */
    BOOL ResizeWindow( void )
    {
        T* pT = static_cast< T* >( this );

        CRect rc;
        pT->GetWindowRect( rc );

        if( !CreateBKImageEx( rc.Width(), rc.Height() ) )
            return FALSE;

        pT->InvalidateRect(rc);

        return TRUE;
    }

    /**
    *@method   SetImage
    *@brief    设置窗口背景图像
    *    
    *@param    UINT nState  详见CONTROL_STATE_IMG定义
    *@param    Image *pImg  指向图像的指针
    *@param    int nx = 0   图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0   图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0   图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0  图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetImage( UINT nState, Image *pImg, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        if( (nState >= WINUI_LAST ) || (nState <= WINUI_FIRST ) || ( NULL == pImg ) )
        {
            return FALSE;
        }

        int width = nWidth==0?pImg->GetWidth():nWidth;
        int height = nHeight==0?pImg->GetHeight():nHeight;

        Bitmap bmp( width, height );
        Graphics graph( &bmp );
        
        graph.DrawImage( pImg, Rect( 0, 0, width, height ), nx, ny, width, height, UnitPixel );
        m_pImage[ nState ] = bmp.Clone( 0, 0, width, height, bmp.GetPixelFormat() );

        return TRUE;
    }

    /**
    *@method   SetImage
    *@brief    设置窗口背景图像
    *    
    *@param    UINT nState   详见CONTROL_STATE_IMG定义
    *@param    UINT uID      图片在资源中存放的ID
    *@param    LPCTSTR sTR   图片在资源中存放的资源标签
    *@param    int nx = 0    图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0    图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0  图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0 图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetImage( UINT nState, UINT uID, LPCTSTR sTR, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        Image *pImage = ImageFromIDResourceEx( uID, sTR );
        if( NULL == pImage )
            return FALSE;
        
        BOOL bRet = SetImage( nState, pImage, nx, ny, nWidth, nHeight );

        delete pImage;
        return bRet;
    }
    
    /**
    *@method   SetImage
    *@brief    设置窗口背景图像
    *    
    *@param    Image *pImg     窗口图像对象
    *@param    int width = 50  截取宽度
    *@param    int height = 50 截取高度
    *@return   BOOL
    */
    BOOL SetImage( Image *pImg, int width = 50, int height = 50 )
    {
        int left = 0;
        int top = 0;

        int halfx = pImg->GetWidth() / 2;
        int halfy = pImg->GetHeight() / 2;

        int right = pImg->GetWidth() - width;
        int bottom = pImg->GetHeight() - height;

        SetImage( WINUI_TOPLEFT, pImg, left, top, width, height );
        SetImage( WINUI_TOP, pImg, halfx, top, width, height );
        SetImage( WINUI_TOPRIGHT, pImg, right, top, width, height );

        SetImage( WINUI_CENTERLEFT, pImg, left, halfy, width, height );
        SetImage( WINUI_CENTER, pImg, halfx, halfy, width, height );
        SetImage( WINUI_CENTERRIGHT, pImg, right, halfy, width, height );

        SetImage( WINUI_BOTTOMLEFT, pImg, left, bottom, width, height );
        SetImage( WINUI_BOTTOM, pImg, halfx, bottom, width, height );
        SetImage( WINUI_BOTTOMRIGHT, pImg, right, bottom, width, height );

        return CheckBKImage();
    }
            
    /**
    *@method   SetImage
    *@brief    设置窗口背景图像
    *    
    *@param    UINT uID         图片在资源中存放的ID
    *@param    LPCTSTR sTR      图片在资源中存放的资源标签
    *@param    int width = 50   截取宽度
    *@param    int height = 50  截取高度
    *@return   BOOL
    */
    BOOL SetImage( UINT uID, LPCTSTR sTR, int width = 50, int height = 50 )
    {
        Image *pImage = ImageFromIDResourceEx( uID, sTR );
        if( NULL == pImage )
            return FALSE;
        
        BOOL bRet = SetImage( pImage, width, height );

        delete pImage;

        return bRet;
    }

    /**
    *@method   OnDrawBKGnd
    *@brief    绘制窗口背景
    *    
    *@param    Graphics &graph  用于作图的画布对象
    *@return   BOOL
    */
    virtual BOOL OnDrawBKGnd(Graphics &graph)
    {
        if( !CheckBKImage() )
        {
            return FALSE;
        }

        T *pT = static_cast< T* >( this );

        //获得当前窗口尺寸
        CRect rc;
        pT->GetWindowRect( rc );

        //使用5填充整个区域
        int nStart = m_pImage[WINUI_CENTERLEFT]->GetWidth();
        int nEnd = rc.Width() - m_pImage[WINUI_CENTERRIGHT]->GetWidth();
        int width = m_pImage[WINUI_CENTER]->GetWidth();
        for( int x = nStart; x < nEnd; x += width )
        {
            if( ( nEnd - x ) < width )
                width = nEnd - x;

            int nTopStart = m_pImage[WINUI_TOP]->GetHeight();
            int nTopEnd = rc.Height() - m_pImage[WINUI_BOTTOM]->GetHeight();
            int height = m_pImage[WINUI_CENTER]->GetHeight();
            for( int y = nTopStart; y < nTopEnd; y += height )
            {
                if( ( nTopEnd - y ) < height )
                    height = nTopEnd - y;

                graph.DrawImage( m_pImage[WINUI_CENTER], Rect( x, y, width, height ), 
                    0, 0, width, height, UnitPixel );
            }
        }

        //画顶端横条
        nStart = m_pImage[WINUI_TOPLEFT]->GetWidth();
        nEnd = rc.Width() - m_pImage[WINUI_TOPRIGHT]->GetWidth();
        width = m_pImage[WINUI_TOP]->GetWidth();
        for( int x = nStart; x < nEnd ; x += width )
        {
            if( ( nEnd - x ) < width )
                width = nEnd - x;

            graph.DrawImage( m_pImage[WINUI_TOP], Rect( x, 0, width, m_pImage[WINUI_TOP]->GetHeight() ),
                0, 0, width, m_pImage[WINUI_TOP]->GetHeight(), UnitPixel );
        }

        //画底部横条
        nStart = m_pImage[WINUI_BOTTOMLEFT]->GetWidth();
        nEnd = rc.Width() - m_pImage[WINUI_BOTTOMRIGHT]->GetWidth();
        width = m_pImage[WINUI_BOTTOM]->GetWidth();
        int top = rc.Height() - m_pImage[WINUI_BOTTOM]->GetHeight();
        for( int x = nStart; x < nEnd ; x += width )
        {
            if( ( nEnd - x ) < width )
                width = nEnd - x;

            graph.DrawImage( m_pImage[WINUI_BOTTOM], Rect( x, top, width, m_pImage[WINUI_BOTTOM]->GetHeight() ),
                0, 0, m_pImage[WINUI_BOTTOM]->GetWidth(), m_pImage[WINUI_BOTTOM]->GetHeight(), UnitPixel );
        }

        //画左部竖条
        nStart = m_pImage[WINUI_TOPLEFT]->GetHeight();
        nEnd = rc.Height() - m_pImage[WINUI_BOTTOMLEFT]->GetHeight();
        int height = m_pImage[WINUI_CENTERLEFT]->GetHeight();
        for( int y = nStart; y < nEnd ; y += height )
        {
            if( ( nEnd - y ) < height )
                height = nEnd - y;

            graph.DrawImage( m_pImage[WINUI_CENTERLEFT], Rect( 0, y, m_pImage[WINUI_CENTERLEFT]->GetWidth(), height ),
                0, 0, m_pImage[WINUI_CENTERLEFT]->GetWidth(), m_pImage[WINUI_CENTERLEFT]->GetHeight(), UnitPixel );
        }

        //画右部竖条
        nStart = m_pImage[WINUI_TOPRIGHT]->GetHeight();
        nEnd = rc.Height() - m_pImage[WINUI_BOTTOMRIGHT]->GetHeight();
        height = m_pImage[WINUI_CENTERRIGHT]->GetHeight();
        int left = rc.Width() - m_pImage[WINUI_CENTERRIGHT]->GetWidth();
        for( int y = nStart; y < nEnd ; y += height )
        {
            if( ( nEnd - y ) < height )
                height = nEnd - y;

            graph.DrawImage( m_pImage[WINUI_CENTERRIGHT], Rect( left, y, m_pImage[WINUI_CENTERRIGHT]->GetWidth(), height ),
                0, 0, m_pImage[WINUI_CENTERRIGHT]->GetWidth(), m_pImage[WINUI_CENTERRIGHT]->GetHeight(), UnitPixel );
        }

        //画4个角
        graph.DrawImage( m_pImage[WINUI_TOPLEFT], Rect( 0, 0, m_pImage[WINUI_TOPLEFT]->GetWidth(), 
            m_pImage[WINUI_TOPLEFT]->GetHeight() ), 
            0, 0, m_pImage[WINUI_TOPLEFT]->GetWidth(), m_pImage[WINUI_TOPLEFT]->GetHeight(), UnitPixel );
        graph.DrawImage( m_pImage[WINUI_TOPRIGHT], Rect( rc.Width() - m_pImage[WINUI_TOPRIGHT]->GetWidth(), 
            0, m_pImage[WINUI_TOPRIGHT]->GetWidth(), m_pImage[WINUI_TOPRIGHT]->GetHeight() ), 
            0, 0, m_pImage[WINUI_TOPRIGHT]->GetWidth(), m_pImage[WINUI_TOPRIGHT]->GetHeight(), UnitPixel );
        graph.DrawImage( m_pImage[WINUI_BOTTOMLEFT], Rect( 0, rc.Height()-m_pImage[WINUI_BOTTOMLEFT]->GetHeight(),
            m_pImage[WINUI_BOTTOMLEFT]->GetWidth(), m_pImage[WINUI_BOTTOMLEFT]->GetHeight() ), 
            0, 0, m_pImage[WINUI_BOTTOMLEFT]->GetWidth(), m_pImage[WINUI_BOTTOMLEFT]->GetHeight(), UnitPixel );
        graph.DrawImage( m_pImage[WINUI_BOTTOMRIGHT], Rect( rc.Width() - m_pImage[WINUI_BOTTOMRIGHT]->GetWidth(), 
            rc.Height()-m_pImage[WINUI_BOTTOMRIGHT]->GetHeight(), m_pImage[WINUI_BOTTOMRIGHT]->GetWidth(), 
            m_pImage[WINUI_BOTTOMRIGHT]->GetHeight() ), 
            0, 0, m_pImage[WINUI_BOTTOMRIGHT]->GetWidth(), m_pImage[WINUI_BOTTOMRIGHT]->GetHeight(), UnitPixel );

        return TRUE;
    }

public:
    typedef enum
    {
        CTRL_BUTTON = 0,    //按钮控件
        CTRL_CHECKBOX,      //CHECKBOX
        CTRL_COMBOBOX,      //COMBOBOX
        CTRL_EDIT,          //EDIT
        CTRL_PROGRESS,      //进度条
        CTRL_RADIOBOX,      //单选按钮
        CTRL_STATIC,        //静态标签
        CTRL_SCROLLBAR,     //滚动条
        CTRL_TABCTRL,       //属性页
    }CTRLTYPE;

protected:
    CSimpleArray< CQsButton * > m_ctlButtons;        //界面上的所有按钮控件列表
    CSimpleArray< CQsCheckBox * > m_ctlCheckBoxs;    //界面上的所有按钮控件列表
    CSimpleArray< CQsRadioBox * > m_ctlRadioBoxs;    //界面上的所有按钮控件列表
    CSimpleArray< CQsComboBox * > m_ctlComboBoxs;    //界面上的所有下列选择控件列表
    CSimpleArray< CQsEdit * > m_ctlEdits;            //界面上的所有下列选择控件列表
    CSimpleArray< CQSProgressBar * > m_ctlProgs; //界面上的所有进度条控件列表
    CSimpleArray< CQsStatic * > m_ctlStaCtrls;   //界面上的所有Static控件列表
    std::vector< HWND > m_vtUnSubclass;         //不需要自动绑定的控件句柄
private:
    
    /**
    *@method   GetCustomObjectEx
    *@brief    获得对象实例
    *    
    *@param    HWND hwnd  根据窗口句柄获得自定义控件对象
    *@return   CCtrlImageMgr *  如果存在,返回对象地址否则返回NULL
    */
    CCtrlImageMgr *GetCustomObjectEx( HWND hwnd )
    {
        CCtrlImageMgr *pcim = NULL;
        for( int i = 0; ( i < m_ctlButtons.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsButton *p = m_ctlButtons[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlCheckBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsCheckBox *p = m_ctlCheckBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlRadioBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsRadioBox *p = m_ctlRadioBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlComboBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsComboBox *p = m_ctlComboBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlEdits.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsEdit *p = m_ctlEdits[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlProgs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQSProgressBar *p = m_ctlProgs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlStaCtrls.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsStatic *p = m_ctlStaCtrls[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CCtrlImageMgr*)p;
                break;
            }
        }

        return pcim;
    }


protected:

    /**
    *@method   GetCustomObject
    *@brief    获得对象实例
    *    
    *@param    HWND hwnd   根据窗口句柄获得自定义控件对象
    *@return   void *      如果存则,返回对象地址否则返回NULL
    */
    void *GetCustomObject( HWND hwnd )
    {
        void *pcim = NULL;
        for( int i = 0; ( i < m_ctlButtons.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsButton *p = m_ctlButtons[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsButton*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlCheckBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsCheckBox *p = m_ctlCheckBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsCheckBox*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlRadioBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsRadioBox *p = m_ctlRadioBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsRadioBox*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlComboBoxs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsComboBox *p = m_ctlComboBoxs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsComboBox*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlEdits.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsEdit *p = m_ctlEdits[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsEdit*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlProgs.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQSProgressBar *p = m_ctlProgs[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQSProgressBar*)p;
                break;
            }
        }

        for( int i = 0; ( i < m_ctlStaCtrls.GetSize() ) && ( NULL == pcim ); i++ )
        {
            CQsStatic *p = m_ctlStaCtrls[i];
            if( p->m_hWnd == hwnd )
            {
                pcim = (CQsStatic*)p;
                break;
            }
        }

        return pcim;
    }
    
    /**
    *@method   GetCustomObject
    *@brief    获得对象实例
    *    
    *@param    UINT uID
    *@return   void *  如果存则,返回对象地址否则返回NULL
    */
    void *GetCustomObject( UINT uID )
    {
        T *pT = static_cast< T* >( this );
        return GetCustomObject( pT->GetDlgItem( uID ) );
    }
    
    /**
    *@method   SetImage
    *@brief    设置控件图像
    *    
    *@param    HWND hwnd
    *@param    UINT nState      详见CTRL_STATE_IMG定义
    *@param    Image *pImage    图片对象
    *@param    int nx = 0       图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0       图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0   图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0  图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetImage( HWND hwnd, UINT nState, Image *pImage, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        CCtrlImageMgr *pcim = GetCustomObjectEx( hwnd );

        if( NULL != pcim )
        {
            return pcim->SetImage( nState, pImage, nx, ny, nWidth, nHeight );
        }

        return FALSE;
    }
    
    /**
    *@method   SetImage
    *@brief    设置控件图像
    *    
    *@param    HWND hwnd
    *@param    UINT nState  详见CTRL_STATE_IMG定义
    *@param    UINT uID     图片在资源中存放的ID
    *@param    LPCTSTR sTR  图片在资源中存放的资源标签
    *@param    int nx = 0   图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0   图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0   图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0  图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetImage( HWND hwnd, UINT nState, UINT uID, LPCTSTR sTR, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        Image *pImage = ImageFromIDResourceEx( uID, sTR );
        if( pImage )
        {
            SetImage( hwnd, nState, pImage, nx, ny, nWidth, nHeight );
            delete pImage;
        }
        return TRUE;
    }
    
    /**
    *@method   SetCtrlIcon
    *@brief    设置控件图标
    *    
    *@param    HWND hwnd
    *@param    UINT nState      详见CTRL_STATE_IMG定义
    *@param    Image *pImage    图片对象
    *@param    int nx = 0       图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0       图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0   图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0  图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetCtrlIcon( HWND hwnd, UINT nState, Image *pImage, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        CCtrlImageMgr *pcim = GetCustomObjectEx( hwnd );

        if( NULL != pcim )
        {
            return pcim->SetCtrlIcon( nState, pImage, nx, ny, nWidth, nHeight );
        }

        return FALSE;
    }
    
    /**
    *@method   SetCtrlIcon
    *@brief    设置控件图标
    *    
    *@param    HWND hwnd
    *@param    UINT nState   详见CTRL_STATE_IMG定义
    *@param    UINT uID      图片在资源中存放的ID
    *@param    LPCTSTR sTR   图片在资源中存放的资源标签
    *@param    int nx = 0    图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0    图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0   图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0  图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetCtrlIcon( HWND hwnd, UINT nState, UINT uID, LPCTSTR sTR, int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        Image *pImage = ImageFromIDResourceEx( uID, sTR );
        if( pImage )
        {
            SetCtrlIcon( hwnd, nState, pImage, nx, ny, nWidth, nHeight );
            delete pImage;
        }
        return TRUE;
    }

private:
    typedef struct _STATEIMAGE
    {
        HWND          hWnd;   //控件句柄
        CTRLTYPE      ct;     //控件类型
        UINT          uState; //状态
        Image         *pImage;//显示图片

        _STATEIMAGE():pImage( NULL )
        {
        }

        ~_STATEIMAGE()
        {
            delete pImage;
        }

    }STATEIMAGE;
    
    CSimpleArray< STATEIMAGE * > m_stImages;  //控件状态图片列表

private:

    /**
    *@method   GetControlImage
    *@brief    获得控件在指定状态下的图片
    *    
    *@param    CTRLTYPE ct  控件类型
    *@param    UINT uState  控件状态
    *@param    HWND hwnd    控件句柄,如果该值为NULL,则返回该控件类型对应状态下的图片
    *@return   Image *      成功返回对应的图片对象,否则返回NULL
    */
    Image *GetControlImage( CTRLTYPE ct, UINT uState, HWND hwnd )
    {
        Image *pImage = NULL;
        int nSize = m_stImages.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            STATEIMAGE *p = m_stImages[i];

            //如果获得控件类型对应状态下的图片
            if( ( ct == p->ct ) && ( uState == p->uState ) )
            {
                pImage = p->pImage;
            }
            
            if( ( ct == p->ct ) && ( uState == p->uState ) && ( hwnd == p->hWnd ) )
            {
                return p->pImage;
            }
        }

        return pImage;
    }

public:
    
    /**
    *@method   SetControlImage
    *@brief    设置控件在指定状态下的图片
    *    
    *@param    CTRLTYPE ct   控件类型
    *@param    UINT uState   控件状态
    *@param    Image *pImage 图片对象
    *@param    HWND hwnd = NULL   
    *@param    int nx = 0         图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0         图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0     图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0    图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetControlImage( CTRLTYPE ct, UINT uState, Image *pImage, HWND hwnd = NULL, 
        int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        int nSize = m_stImages.GetSize();
        for( int i = 0; i < nSize; i++ )
        {
            STATEIMAGE *p = m_stImages[i];
            if( ( ct == p->ct ) && ( uState == p->uState ) && ( hwnd == p->hWnd ) )
            {
                delete p;
                m_stImages.RemoveAt( i );
                break;
            }
        }

        STATEIMAGE *p = new STATEIMAGE;
        p->hWnd = hwnd;
        p->ct = ct;
        p->uState = uState;

        //复制图片
        int width = nWidth==0?pImage->GetWidth():nWidth;
        int height = nHeight==0?pImage->GetHeight():nHeight;

        Bitmap bmp( width, height );
        Graphics graph( &bmp );
        
        graph.DrawImage( pImage, Rect( 0, 0, width, height ), nx, ny, width, height, UnitPixel );
        bmp.Clone(0, 0, width, height, bmp.GetPixelFormat() );
        p->pImage = bmp.Clone( 0, 0, width, height, bmp.GetPixelFormat() );

        m_stImages.Add( p );

        return TRUE;
    }

    /**
    *@method   SetControlImage
    *@brief    设置控件在指定状态下的图片
    *    
    *@param    CTRLTYPE ct   控件类型
    *@param    UINT uState   控件状态
    *@param    UINT uID      图片在资源中存放的ID
    *@param    LPCTSTR sTR   图片在资源中存放的资源标签
    *@param    HWND hwnd = NULL
    *@param    int nx = 0    图像范围--左上点的X坐标,默认为0
    *@param    int ny = 0    图像范围--左上点的Y坐标,默认为0
    *@param    int nWidth = 0    图像范围--宽度,默认为0,此时为图像的宽度
    *@param    int nHeight = 0   图像范围--高度,默认为0,此时为图像的高度
    *@return   BOOL
    */
    BOOL SetControlImage( CTRLTYPE ct, UINT uState, UINT uID, LPCTSTR sTR, HWND hwnd = NULL, 
        int nx = 0, int ny = 0, int nWidth = 0, int nHeight = 0 )
    {
        Image *pImage = ImageFromIDResourceEx( uID, sTR );
        if( NULL == pImage )
            return FALSE;

        return SetControlImage( ct, uState, pImage, hwnd, nx, ny, nWidth, nHeight );
    }

    /**
    *@method   SubclassAllControls
    *@brief    将窗口上的所有控件进行关联
    *    
    *@param    void
    *@return   BOOL
    */
    BOOL SubclassAllControls( void )
    {
        T* pT = static_cast< T* > ( this );
        return ::EnumChildWindows( pT->m_hWnd, EnumChildProc, ( LPARAM ) this );
    }

    /**
    *@method   UnSubclassControl
    *@brief    根据控件类型对控件进行关联
    *    
    *@param    HWND hwnd  hwnd 控件句柄
    *@return   void
    */
    void UnSubclassControl( HWND hwnd )
    {
        m_vtUnSubclass.push_back( hwnd );
    }

    /**
    *@method   SubclassWindow
    *@brief    根据控件类型对控件进行关联
    *    
    *@param    HWND hwnd    控件句柄
    *@param    CTRLTYPE ct  控件类型
    *@return   BOOL
    */
    virtual BOOL SubclassWindow( HWND hwnd, CTRLTYPE ct )
    {
        //判断该句柄是否在不邦定列表中
        for( size_t i = 0; i < m_vtUnSubclass.size(); i++ )
        {
            if( m_vtUnSubclass[i] == hwnd )
            {
                return TRUE;
            }
        }

        T *pT = static_cast< T * > ( this );
        ATL::CWindow cw( hwnd );
        if( cw.GetParent().m_hWnd != pT->m_hWnd )
            return TRUE;

        Image* pImg = NULL;
        switch( ct )
        {
        case CTRL_BUTTON:
            {
                CQsButton *pCtrl = new CQsButton;
                pCtrl->SubclassWindow( hwnd );
                m_ctlButtons.Add( pCtrl );

                break;
            }
        case CTRL_CHECKBOX:
            {
                CQsCheckBox *pCtrl = new CQsCheckBox;
                pCtrl->SubclassWindow( hwnd );
                m_ctlCheckBoxs.Add( pCtrl );

                break;
            }
        case CTRL_RADIOBOX:
            {
                CQsRadioBox *pCtrl = new CQsRadioBox;
                pCtrl->SubclassWindow( hwnd );
                m_ctlRadioBoxs.Add( pCtrl );
                break;
            }
        case CTRL_COMBOBOX:
            {
                CQsComboBox *pCtrl = new CQsComboBox;
                pCtrl->SubclassWindow( hwnd );
                m_ctlComboBoxs.Add( pCtrl );
                break;
            }
        case CTRL_EDIT:
            {
                CQsEdit *pCtrl = new CQsEdit;
                pCtrl->SubclassWindow( hwnd );
                m_ctlEdits.Add( pCtrl );
                break;
            }
        case CTRL_PROGRESS:
            {
                CQSProgressBar *pCtrl = new CQSProgressBar;
                pCtrl->SubclassWindow( hwnd );

                m_ctlProgs.Add( pCtrl );
                break;
            }
        case CTRL_STATIC:
            {
                CQsStatic *pCtrl = new CQsStatic;
                pCtrl->SubclassWindow( hwnd );

                m_ctlStaCtrls.Add( pCtrl );             
                break;
            }
        }

        return TRUE;
    }

    /**
    *@method   EnumChildProc
    *@brief    控件遍历回调函数
    *    
    *@param    HWND hwnd
    *@param    LPARAM lParam
    *@return   BOOL CALLBACK
    */
    static BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lParam )
    {
        CQsSkinWindowUI< T, _bIsChildWnd > *pThis = ( CQsSkinWindowUI< T, _bIsChildWnd > * )lParam;

        CString strClass;
        GetClassName( hwnd, strClass.GetBuffer( 64 ), 64 );

        strClass.MakeUpper();

        if( strClass == _T("BUTTON") )
        {
            LONG lStyle = GetWindowLong( hwnd, GWL_STYLE );

            if( ( lStyle & BS_CHECKBOX ) == BS_CHECKBOX )
            {
                return pThis->SubclassWindow( hwnd, CTRL_CHECKBOX );
            }
            else if( ( lStyle & BS_AUTOCHECKBOX ) == BS_AUTOCHECKBOX )
            {
                return pThis->SubclassWindow( hwnd, CTRL_CHECKBOX );
            }
            else if( ( lStyle & BS_AUTORADIOBUTTON ) == BS_AUTORADIOBUTTON )
            {
                return pThis->SubclassWindow( hwnd, CTRL_RADIOBOX );
            }
            else if( ( lStyle & BS_GROUPBOX ) == BS_GROUPBOX )
            {
                
            }
            else if( ( lStyle & BS_RADIOBUTTON ) == BS_RADIOBUTTON )
            {
                return pThis->SubclassWindow( hwnd, CTRL_RADIOBOX );
            }
            else
            {
                return pThis->SubclassWindow( hwnd, CTRL_BUTTON );
            }

        }
        else if( strClass == _T( "COMBOBOX" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_COMBOBOX );
        }
        else if( strClass == _T( "EDIT" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_EDIT );
        }
        else if( strClass == _T( "MSCTLS_PROGRESS32" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_PROGRESS );
        }
        else if( strClass == _T( "SCROLLBAR" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_SCROLLBAR );
        }
        else if( strClass == _T( "SYSTABCONTROL32" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_TABCTRL );
        }
        else if( strClass == _T( "STATIC" ) )
        {
            return pThis->SubclassWindow( hwnd, CTRL_STATIC );
        }

        return TRUE;
    }

    /**
    *@method   ImageFromIDResourceEx
    *@brief    从资源中读取图像
    *    
    *@param    UINT nID      资源ID
    *@param    LPCTSTR sTR   资源标签名
    *@return   Image *   成功返回读取到的图片对象,否则返回NULL
    */
    Image *ImageFromIDResourceEx(UINT nID, LPCTSTR sTR)
    {
        Image *pImage;
        HINSTANCE hIns = _AtlBaseModule.GetResourceInstance();
        HRSRC hRsrc = ::FindResource (hIns,MAKEINTRESOURCE(nID),sTR); // type
        if (!hRsrc)
            return NULL;

        // load resource into memory
        DWORD len = SizeofResource(hIns, hRsrc);
        BYTE* lpRsrc = (BYTE*)LoadResource(hIns, hRsrc);
        if (!lpRsrc)
            return NULL;

        // Allocate global memory on which to create stream
        HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
        BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
        IStream* pstm;

        memcpy(pmem,lpRsrc,len);
        if(CreateStreamOnHGlobal(m_hMem,FALSE,&pstm) != S_OK)
            return NULL;
        
        // load from stream
        pImage=Gdiplus::Image::FromStream(pstm);

        GlobalUnlock(m_hMem);
        pstm->Release();
        FreeResource(lpRsrc);

        GlobalFree(m_hMem);

        return pImage;
    }

    /**
    *@method   SetCtrlText
    *@brief    设置控件显示文字
    *    
    *@param    int nCtrlID   控件ID
    *@param    LPCTSTR strText  要设置的文字
    *@return   BOOL
    */
    BOOL SetCtrlText( int nCtrlID, LPCTSTR strText )
    {
        T *pT = static_cast< T* >( this );
        ATL::CWindow cw = pT->GetDlgItem( nCtrlID );
        if( !cw.IsWindow() )
            return FALSE;

        WTL::CString strClass;
        GetClassName( cw.m_hWnd, strClass.GetBuffer( 64 ), 64 );
        strClass.MakeUpper();

        if( strClass == _T( "COMBOBOX" ) )
        {
            DWORD dwStyle = cw.GetWindowLong( GWL_STYLE );
            if( ( dwStyle & CBS_DROPDOWNLIST ) )
            {
                WTL::CComboBox cb = cw.m_hWnd;
                for( int i = 0; i < cb.GetCount(); i++ )
                {
                    WTL::CString strTemp;
                    cb.GetLBText( i, strTemp );
                    if( strTemp == strText )
                    {
                        cb.SetCurSel( i );
                        break;
                    }
                }
            }
            else
            {
                cw.SetWindowText( strText );

                CRect rc;
                cw.GetWindowRect( rc );
                pT->ScreenToClient( rc );
                pT->InvalidateRect( rc, TRUE );

            }
        }
        else
        {
            cw.SetWindowText( strText );

            CRect rc;
            cw.GetWindowRect( rc );
            pT->ScreenToClient( rc );
            pT->InvalidateRect( rc, TRUE );
        }


        return TRUE;
    }

    /**
    *@method   SetCtrlText
    *@brief    设置控件显示文字
    *    
    *@param    int nCtrlID  控件ID
    *@param    int nTextID  要设置的文字在资源中的ID
    *@return   BOOL
    */
    BOOL SetCtrlText( int nCtrlID, int nTextID )
    {
        CString strText;
        strText.LoadString( nTextID );

        return SetCtrlText( nCtrlID, strText );
    }

    /**
    *@method   GetCtrlText
    *@brief    获得控件文字
    *    
    *@param    int nCtrlID   控件ID
    *@return   WTL::CString  控件文字
    */
    CString GetCtrlText( int nCtrlID )
    {
        CString strText;

        T* pT = static_cast< T* >( this );
        ATL::CWindow cw = pT->GetDlgItem( nCtrlID );
        if( !cw.IsWindow() )
            return strText;

        int len = cw.GetWindowTextLength() + 1;
        cw.GetWindowText( strText.GetBuffer( len ), len );
        strText.ReleaseBuffer();

        return strText;
    }

    /**
    *@method   SetCtrlFont
    *@brief    设置控件制定状态下文字字体
    *    
    *@param    int nCtrlID        控件ID
    *@param    UINT uState = 0    状态ID
    *@param    LPCTSTR lpszFaceName = _T("宋体")   字体
    *@param    int nHeight = 12               字体高度
    *@param    int fnWeight = FW_NORMAL     
    *@param    BYTE bItalic = FALSE           斜体字
    *@param    BYTE bUnderline = FALSE        下划线
    *@param    BYTE bStrikeOut = FALSE        删除线
    *@return   BOOL
    */
    BOOL SetCtrlFont( int nCtrlID, UINT uState = 0, LPCTSTR lpszFaceName = _T( "宋体" ), 
        int nHeight = 12, int fnWeight = FW_NORMAL, BYTE bItalic = FALSE, 
        BYTE bUnderline = FALSE, BYTE bStrikeOut = FALSE )
    {
        T *pT = static_cast< T* >( this );
        HWND hwnd = pT->GetDlgItem( nCtrlID );

        CCtrlImageMgr *pcim = ( CCtrlImageMgr* )GetCustomObjectEx( hwnd );
        if( pcim )
        {
            pcim->SetStateFont( uState, lpszFaceName, nHeight, fnWeight, bItalic, bUnderline, bStrikeOut );
            return TRUE;
        }
        else
        {
            return FALSE;
        }

    }

    /**
    *@method   SetFontColor
    *@brief    设置指定状态下字体的颜色
    *    
    *@param    HWND hwnd     控件句柄
    *@param    UINT uState   状态值
    *@param    COLORREF rgb  字体颜色
    *@return   BOOL
    */
    BOOL SetFontColor( HWND hwnd, UINT uState, COLORREF rgb )
    {
        CCtrlImageMgr *pcim = ( CCtrlImageMgr* )GetCustomObjectEx( hwnd );
        if( pcim )
        {
            pcim->SetFontColor( uState, rgb );
            return TRUE;
        }
        else
        {
            return FALSE;
        }

    }
    
    /**
    *@method   SetFontColor
    *@brief    设置指定状态下字体的颜色
    *    
    *@param    int nCtrlID     控件ID
    *@param    UINT uState     状态值
    *@param    COLORREF rgb    字体颜色
    *@return   BOOL
    */
    BOOL SetFontColor( int nCtrlID, UINT uState, COLORREF rgb )
    {
        T *pT = static_cast< T* >( this );
        HWND hwnd = pT->GetDlgItem( nCtrlID );

        return SetFontColor( hwnd, uState, rgb );
    }

    void ReDraw( )
    {
        delete m_pBKImage;
        m_pBKImage = NULL;

        T *pT = static_cast< T* >( this );
        if ( pT->IsWindow())
        {
            pT->Invalidate( );

            HWND hChild = FindWindowEx( pT->m_hWnd, NULL, NULL, NULL );
            while ( NULL != hChild )
            {
                ::SendMessage( hChild, WM_REDRAWBKGND, 0, 0 );
                hChild = FindWindowEx( pT->m_hWnd, hChild, NULL, NULL  );
            }
        }
    }
};