WTL学习笔记(5)系统皮肤管理
2011-08-16 22:26 Clingingboy 阅读(2590) 评论(0) 收藏 举报
首先下载一个Demo看一下效果
http://www.codeproject.com/KB/winsdk/xpvisualstyle.aspx
概念:每个控件都有Part和State的概念,这个同在wpf和silverlight的visual state的概念是相同的。只不过silverlight可以手写xaml,而传统win32只能函数获取样式
如checkbox的状态,操作系统其实定义了多个状态的图片,根据状态不同进行切换而已
每个控件都有自己的皮肤特性,如上checkbox各种状态的样式,可借助DrawThemeBackground等方法将控件部分状态样式输出
wtl的CTheme和CThemeImpl对内置的win32相关的theme函数进行了封装
CTheme属于原生封装,CThemeImpl则是进行了加工.使用起来更加方便.
自定义控件下Theme的使用
如金山开源控件库中,虽然重绘了button等控件,但并非全部控件重新定义.如radiobutton和checkbox就可以使用内置的控件样式.为了不使用内置的创建方法创建这些控件,那么就可以基于自己的架构之上,再结合Theme相关函数绘制需要的控件.
示例
1.CBkWinTheme的封装
该类是金山卫士下的一个文件bkwin\bktheme.h
其功能同wtl的CTheme,对局部的几个重要的函数进行了轻量封装
需要注意的是使用uxtheme.dll,是以载入dll的方式来进行的,最常用的方法莫过于DrawThemeBackground
//////////////////////////////////////////////////////////////////////////
//  Class Name: BkTheme
// Description: Windows Theme(XP later)
//     Creator: ZhangXiaoxuan
//     Version: 2009.5.12 - 1.0 - Create
//////////////////////////////////////////////////////////////////////////
#pragma once
#include <atlcoll.h>
#include <Uxtheme.h>
#include <tmschema.h>
class BkWinThemeFunc
{
    typedef HTHEME (WINAPI *FnOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
    typedef HRESULT (WINAPI *FnCloseThemeData)(HTHEME hTheme);
    typedef HRESULT (WINAPI *FnDrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
    typedef HRESULT (WINAPI *FnSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
public:
    BkWinThemeFunc()
        : m_bThemeValid(FALSE)
        , m_pfnOpenThemeData(NULL)
        , m_pfnCloseThemeData(NULL)
        , m_pfnDrawThemeBackground(NULL)
        , m_pfnSetWindowTheme(NULL)
    {
        HMODULE hModTheme = ::GetModuleHandle(_T("uxtheme.dll"));
        if (!hModTheme)
            return;
        m_bThemeValid = TRUE;
        m_pfnOpenThemeData          = (FnOpenThemeData)::GetProcAddress(hModTheme, "OpenThemeData");
        m_pfnCloseThemeData         = (FnCloseThemeData)::GetProcAddress(hModTheme, "CloseThemeData");
        m_pfnDrawThemeBackground    = (FnDrawThemeBackground)::GetProcAddress(hModTheme, "DrawThemeBackground");
        m_pfnSetWindowTheme         = (FnSetWindowTheme)::GetProcAddress(hModTheme, "SetWindowTheme");
    }
    static BOOL IsValid()
    {
        return _Instance()->m_bThemeValid;
    }
    static HTHEME OpenThemeData(HWND hwnd, LPCWSTR pszClassList)
    {
        if (_Instance()->m_pfnOpenThemeData)
        {
            return _Instance()->m_pfnOpenThemeData(hwnd, pszClassList);
        }
        else
            return NULL;
    }
    static HRESULT CloseThemeData(HTHEME hTheme)
    {
        if (_Instance()->m_pfnCloseThemeData)
        {
            return _Instance()->m_pfnCloseThemeData(hTheme);
        }
        else
            return E_NOTIMPL;
    }
    static HRESULT DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect)
    {
        if (_Instance()->m_pfnDrawThemeBackground)
        {
            return _Instance()->m_pfnDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
        }
        else
            return E_NOTIMPL;
    }
    static HRESULT SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList)
    {
        if (_Instance()->m_pfnSetWindowTheme)
        {
            return _Instance()->m_pfnSetWindowTheme(hwnd, pszSubAppName, pszSubIdList);
        }
        else
            return E_NOTIMPL;
    }
    enum
    {
        BkThemeNameButton = 0, 
        BkThemeNameEnd, 
    };
    static LPCWSTR ThemeName(int nID)
    {
        static const LPCWSTR Names[] =
        {
            L"BUTTON",
            L"",
        };
        static int NamesCount = sizeof(Names) / sizeof(LPCWSTR) - 1;
        if (nID >= 0 && nID < NamesCount)
            return Names[BkThemeNameButton];
        else
            return NULL;
    }
private:
    BOOL m_bThemeValid;
    FnOpenThemeData         m_pfnOpenThemeData;
    FnCloseThemeData        m_pfnCloseThemeData;
    FnDrawThemeBackground   m_pfnDrawThemeBackground;
    FnSetWindowTheme        m_pfnSetWindowTheme;
    static BkWinThemeFunc* ms_pInstance;
    static BkWinThemeFunc* _Instance()
    {
        if (!ms_pInstance)
            ms_pInstance = new BkWinThemeFunc;
        return ms_pInstance;
    }
//     static BkWinThemeFunc& _Instance()
//     {
//         static BkWinThemeFunc s_obj;
// 
//         return s_obj;
//     }
};
__declspec(selectany) BkWinThemeFunc* BkWinThemeFunc::ms_pInstance = NULL;
template<int t_nThemeId, int t_partid>
class CBkWinTheme
{
public:
    CBkWinTheme(HWND hWnd = NULL)
        : m_hTheme(NULL)
    {
        if (hWnd)
            OpenTheme(hWnd);
    }
    ~CBkWinTheme()
    {
        BkWinThemeFunc::CloseThemeData(m_hTheme);
    }
    BOOL IsValid()
    {
        return (NULL != m_hTheme);
    }
    BOOL OpenTheme(HWND hWnd)
    {
        if (m_hTheme)
            return FALSE;
        m_hTheme = BkWinThemeFunc::OpenThemeData(NULL, BkWinThemeFunc::ThemeName(t_nThemeId));
        if (m_hTheme)
            return TRUE;
        return FALSE;
    }
    void DrawBackground(HDC hdc, int iStateId, const RECT *pRect)
    {
        BkWinThemeFunc::DrawThemeBackground(m_hTheme, hdc, t_partid, iStateId, pRect, NULL);
    }
protected:
    HTHEME m_hTheme;
};
typedef CBkWinTheme<BkWinThemeFunc::BkThemeNameButton, BP_CHECKBOX> CBkCheckBoxTheme;
typedef CBkWinTheme<BkWinThemeFunc::BkThemeNameButton, BP_RADIOBUTTON> CBkRadioBoxTheme;
2.checkbox和radiobox的实现
CBkWindow 之前有讲到过,这里只贴相关OnPaint方法,请先忽略其他,只注意theme的DrawBackground方法,刚好可以用到此处.
class CBkCheckBox : public CBkWindow
{
    BKOBJ_DECLARE_CLASS_NAME(CBkCheckBox, "check")
public:
    CBkCheckBox()
        : m_theme()
    {
    }
    void OnPaint(CDCHandle dc)
    {
        CRect rcCheckBox = m_rcWindow;
        rcCheckBox.right = rcCheckBox.left + CheckBoxSize;
        m_theme.OpenTheme(m_hWndContainer);
        if (m_theme.IsValid())
        {
            m_theme.DrawBackground(dc, _GetDrawState(), rcCheckBox);
        }
        else
        {
            dc.DrawFrameControl(rcCheckBox, DFC_BUTTON, _GetDrawState());
        }
        m_rcWindow.left += CheckBoxSize + CheckBoxSpacing;
        m_style.m_nTextAlign &= ~DT_BOTTOM;
        m_style.m_nTextAlign |= DT_VCENTER;
        __super::OnPaint(dc);
        m_rcWindow.left -= CheckBoxSize + CheckBoxSpacing;
    }
   
protected:
    CBkCheckBoxTheme m_theme;
    };
class CBkRadioBox : public CBkWindow
{
    BKOBJ_DECLARE_CLASS_NAME(CBkRadioBox, "radio")
  
public:
    CBkRadioBox()
        : m_theme()
    {
    }
   
    virtual BOOL Load(TiXmlElement* pTiXmlElem)
    {
        if (!CBkWindow::Load(pTiXmlElem))
            return FALSE;
        return BkWnds::RegisterRadioGroup(this, m_strGroup);;
    }
    void OnPaint(CDCHandle dc)
    {
     
        m_theme.OpenTheme(m_hWndContainer);
        if (m_theme.IsValid())
        {
            m_theme.DrawBackground(dc, _GetDrawState(), rcCheckBox);
        }
        else
        {
            dc.DrawFrameControl(rcCheckBox, DFC_BUTTON, _GetDrawState());
        }
      
        __super::OnPaint(dc);
           }
   
protected:
    CBkRadioBoxTheme m_theme;
   };
这也算是一种办法,如果只想创建部分控件样式又想利用原有的控件样式的话,可以利用此法,记录一下
                    
                

                
            
        
浙公网安备 33010602011771号