zoukankan      html  css  js  c++  java
  • WTL学习笔记(5)系统皮肤管理

    首先下载一个Demo看一下效果

    http://www.codeproject.com/KB/winsdk/xpvisualstyle.aspx

    概念:每个控件都有Part和State的概念,这个同在wpf和silverlight的visual state的概念是相同的。只不过silverlight可以手写xaml,而传统win32只能函数获取样式

    如checkbox的状态,操作系统其实定义了多个状态的图片,根据状态不同进行切换而已

    image

    image

    每个控件都有自己的皮肤特性,如上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;
    
       };

    这也算是一种办法,如果只想创建部分控件样式又想利用原有的控件样式的话,可以利用此法,记录一下

  • 相关阅读:
    the-backdoor-factory安装
    python 实验普通IO和多路复用IO
    vue学习随笔(一)
    CentOS最小安装
    CentOS7安装ELK实践(二)
    CentOS7安装ELK实践(一)
    【转】mysql 多主多从配置,自增id解决方案
    Istio组件解析
    Kubernetes NetworkPolicy 插件支持
    在Kubernetes集群上安装Metrics Server
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2141603.html
Copyright © 2011-2022 走看看