65.9K
CodeProject 正在变化。 阅读更多。
Home

用 WTL 喝一杯!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.99/5 (23投票s)

2007年5月31日

CPL

5分钟阅读

viewsIcon

146899

downloadIcon

3641

为您的原生 (WTL) 应用程序启用 Aero glass 并保持向后兼容。

How do you like it?

引言

抱歉,这里没什么可喝的。

但是,如果您喜欢 Vista Aero 玻璃效果并希望在您的(现有或新的)WTL 应用程序中启用它,本文旨在(并希望)帮助您。

原生 API 可以很容易地投入使用,并且 aero 命名空间允许对现有软件进行简单修改。

本文由两部分组成

  1. 入门指南将介绍一些 WTL::aero:: 类的用法和产生效果
  2. WTL::aero 命名空间内部是对工具集的更详细描述

参考文献

这里使用的原生 API 的主要文档是 MSDN 桌面窗口管理器 部分。

您可以在 CodeProject 中找到 Michael Dunn 的文章:C++ 中的 Vista 炫酷功能:在 UI 中使用玻璃效果,以及 Kenny Kerr 的博客 桌面窗口管理器控件和桌面窗口管理器

在我准备这篇文章时,Stefan Kuhr 发表了一篇 MFC 姊妹文章 向旧版 Windows 应用程序添加或改造 Aero 玻璃效果

必备组件

要阅读本文,您需要在计算机上正确安装以下软件

显然您应该在 Vista 机器上测试,但您可以在 XP SP2 下编译和运行所有内容。

入门指南

对于任何启用 aero 的应用程序

使用 WTL AppWizard 创建一个简单的 FirstTest 应用程序:只需在第一个向导屏幕上单击“下一步”,取消选中“使用视图”框,然后单击“完成”。现在进行一些简单的更改,这些步骤总是需要完成的

  1. 更改 stdafx.h 中的常量

    // stdafx.h : include file for the standard system include files,
    //  or project specific include files that are used frequently, but
    //      are changed infrequently
    
    #pragma once
    
    // Change these values to use different versions
    #define WINVER           0x0600
    #define _WIN32_WINNT     0x0600
    #define _WIN32_IE        0x0700
    #define _RICHEDIT_VER    0x0200
    // ...
    

  2. toolbar.bmpWtlAero.zip 解压到您的项目文件夹 FirstTest\res\ 中。
  3. WtlAero.hWtlAero.zip 解压到您的项目文件夹 FirstTest\ 中,并修改 FirstTest.cpp 以包含它

    // FirstTest.cpp : main source file for FirstTest.exe
    
    #include "stdafx.h"
    
    #include<atlframe.h>
    #include <atlctrls.h>
    #include <atldlgs.h>
    #include <atlctrlw.h>
    
    #include "WtlAero.h"
    
    #include "resource.h"
    
    // ...
  4. MainFrm.h 中,将 CFrameWindowImplm_CmdBar 的定义更改为它们对应的 aero:: 版本

    // MainFrm.h : interface of the CMainFrame class
    //
    ////////////////////////////////////////////////////////////////
    #pragma once
    
    class CMainFrame : public aero::CFrameWindowImpl<CMainFrame>,
        public CUpdateUI<CMainFrame>,
        public CMessageFilter, public CIdleHandler
    {
    public:
        DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
    
        CFirstTestView m_view;
    
        aero::CCommandBarCtrl m_CmdBar;
    
    // ...
    

  5. 在消息映射中更改基类定义,并将其移到 OnCreate() 处理程序之前
    BEGIN_MSG_MAP(CMainFrame)
     CHAIN_MSG_MAP(aero::CFrameWindowImpl<CMainFrame>)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
     MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
     COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
     COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
     COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
     COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
     COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
     CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
    END_MSG_MAP()

  6. 如果您想在 XP 或 W2k 下运行应用程序,请为 uxtheme.dlldwmapi.dll 设置延迟加载

    Screenshot - Delayload.jpg

  7. 就这样。编译并运行。您应该会得到这个。

    Screenshot - FirstTest.jpg

让我们用这个首次测试做更多的事情

  • 要将工具栏更改为透明的,只需在 CMainFrame::OnCreate() 中替换对 CreateSimpleToolBarCtrl() 的调用
    HWND hWndToolBar = CreateAeroToolBarCtrl(m_hWnd,
      IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
    

    Screenshot - FirstTestTB.jpg

  • 要进行一些绘图,请在 CMainFrame 中插入此成员

    void Paint(CDCHandle dc, RECT& rClient, RECT& rView, RECT& rDest)
    {
        CLogFont lf;
    
        GetThemeSysFont(TMT_MSGBOXFONT, &lf);
        lf.lfHeight *= 3;
        CFont f = lf.CreateFontIndirect();
    
        HFONT hfOld = dc.SelectFont(f);
    
    
        DrawText(dc, L"Hello Aero", &rClient, DT_CENTER | DT_VCENTER |
            DT_SINGLELINE);
        dc.SelectFont(hfOld);
     }

    Screenshot - FirstTestHello.jpg

获取 Aero 关于对话框

  1. 在资源编辑器中,打开 IDD_ABOUTBOX 对话框并将图标和文本控件 ID 更改为 IDC_APPICONIDC_APPTEXT
  2. 更改 aboutdlg.h 中的代码

    // aboutdlg.h : interface of the CAboutDlg class
    //...
    class CAboutDlg : public aero::CDialogImpl<CAboutDlg >
    {
    public:
        enum { IDD = IDD_ABOUTBOX };
    
        BEGIN_MSG_MAP(CAboutDlg)
            CHAIN_MSG_MAP(aero::CDialogImpl<CAboutDlg >)
            MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
            COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
            COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
        END_MSG_MAP()
    
    //...
        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/,
            LPARAM /*lParam*/, BOOL& /*bHandled*/)
        {
            CenterWindow(GetParent());
            AERO_CONTROL(CStatic, m_Icon, IDC_APPICON)
            AERO_CONTROL(CStatic, m_Text, IDC_APPTEXT)
            AERO_CONTROL(CButton, m_OK, IDOK)
            return TRUE;
        }
    //...
    

    Screenshot - FirstTestAbout.jpg

Aero 示例

AeroSamples 项目中,您可以找到其他 aero 适配的 AppWizard 应用程序

  • AeroFrame 与您的 FirstTest 相同
  • AeroView 使用一个简单的 WTL 视图类。对 CMainFrameCAboutDlg 的更改是相同的,CAeroView::Paint() 也可以在未应用主题的运行时环境中工作

    // AeroView.h : interface of the CAeroView class
    //
    //////////////////////////////////////////////////////////////
    class CAeroView : public aero::CWindowImpl<CAeroView>
    {
    public:
        DECLARE_WND_CLASS(NULL)
    
        BOOL PreTranslateMessage(MSG* pMsg)
        {
            pMsg;
            return FALSE;
        }
    
        void Paint(CDCHandle dc, RECT& rClient, RECT& rView, RECT& rDest)
        {
            CLogFont lf;
    
            if (IsTheming())
            {
                GetThemeSysFont(TMT_MSGBOXFONT, &lf);
                if (!aero::IsSupported())
                    DrawThemeBackground(dc, 1, 1, &rClient, &rDest);
            }
            else
            {
                NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };
                SystemParametersInfo ( SPI_GETNONCLIENTMETRICS,
                    sizeof(NONCLIENTMETRICS), &ncm, false );
                lf = ncm.lfMessageFont;
                dc.FillSolidRect(&rClient, GetSysColor(COLOR_WINDOW));
            }
    
            lf.lfHeight *= 3;
            CFont f = lf.CreateFontIndirect();
            HFONT hfOld = dc.SelectFont(f);
            DrawText(dc, L"Hello Aero", &rClient,
               DT_CENTER | DT_VCENTER | DT_SINGLELINE);
            dc.SelectFont(hfOld);
        }
    
        BEGIN_MSG_MAP(CAeroView)
            CHAIN_MSG_MAP(aero::CWindowImpl<CAeroView>)
        END_MSG_MAP()
    };

  • AeroTab 是一个“AppWizard 选项卡视图应用程序”,使用与 CAeroView 相同的类,其中 CTabViewaero::CTabView 替换。

    Screenshot - AeroTab.jpg

  • AeroSplit 是一个“AppWizard 资源管理器应用程序”,在 MainFrm.h 中的向导生成代码中进行了一些额外更改

    class CMainFrame : public aero::CFrameWindowImpl<CMainFrame>,
       public CUpdateUI<CMainFrame>,
       public CMessageFilter, public CIdleHandler
    {
    public:
        DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
    
        aero::CSplitterWindow m_splitter;
        aero::CPaneContainer m_pane;
        aero::CCtrl<CTreeViewCtrl> m_treeview;
        CAeroView m_view;
        aero::CCommandBarCtrl m_CmdBar;
    //...
        LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,
            BOOL& /*bHandled*/)
        {
    //...
          m_treeview.SetWindowTheme(L"explorer", NULL);
          HTREEITEM hti = m_treeview.InsertItem(L"Test", TVI_ROOT, TVI_LAST);
          m_treeview.InsertItem(L"Child Test", hti, TVI_LAST);
    //...
    

    Screenshot - AeroSplit.jpg

  • AeroDialog 是一个“模态对话框 AppWizard 应用程序”,在对话框编辑器中添加了一些控件

    // MainDlg.h : interface of the CMainDlg class
    //
    //////////////////////////////////////////////////////////////////////
    
    #pragma once
    
    class CMainDlg : public aero::CDialogImpl<CMainDlg>
    {
    public:
        enum { IDD = IDD_MAINDLG };
    
        BEGIN_MSG_MAP(CMainDlg)
            CHAIN_MSG_MAP(aero::CDialogImpl<CMainDlg>)
    //...
        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                    LPARAM /*lParam*/, BOOL& /*bHandled*/)
        {
        //...
            AERO_CONTROL(CButton, m_OK, IDOK)
            AERO_CONTROL(CButton, m_Cancel, IDCANCEL)
            AERO_CONTROL(CButton, m_About, ID_APP_ABOUT)
            AERO_CONTROL(CEdit, m_Edit, IDC_EDIT1)
            AERO_CONTROL(CButton, m_C1, IDC_CHECK1)
            AERO_CONTROL(CButton, m_C2, IDC_CHECK2)
            AERO_CONTROL(CButton, m_R1, IDC_RADIO1)
            AERO_CONTROL(CButton, m_R2, IDC_RADIO2)
            AERO_CONTROL(CButton, m_Group, IDC_GROUP)
            AERO_CONTROL(CListBox, m_LB, IDC_LIST1)
            AERO_CONTROL(CComboBox, m_CB, IDC_COMBO1)
    
            m_LB.AddString(L"TEST Item");
            m_CB.AddString(L"Combo Test");
    
            SetOpaqueUnder(IDC_MONTHCALENDAR1);
    
            return TRUE;
        }
    //...

    Sorry, it's partly in french :)

WTL::aero 命名空间内部

WTL::aero 命名空间提供了使任何 WTL 应用程序支持 aero 玻璃效果的工具集。

命名空间函数

这些函数执行运行时测试以实现向后兼容性。

  • bool aero::IsSupported():如果此函数返回 false,则不要尝试任何操作
  • bool aero::IsComposing():如果此函数返回 true,则继续执行
  • bool aero::IsOpaqueBlend():如果此函数返回 true,则 Vista 透明度已关闭
  • template <class TCtrl> BOOL aero::Subclass(TCtrl& Ctrl, HWND hCtrl) 仅当 aero::IsSupported() 时才使用 TCtrl 类型 CtrlhCtrl 控件进行子类化

基类

基类是库的引擎。

  • aero::CAeroBase 使其派生类可以访问 Theme API。Subclass() 成员接受一个控件 ID,并对其 HWND 调用 aero::Subclass()。各种 DrawText() 成员在半透明背景上绘图时使用 ::DrawThemeTextEx()

    ///////////////////////////////////////////////////////////////////////
    // aero::CAeroBase - Base class for Aero translucency (when available)
    
    template <class T>
    class CAeroBase :
        public WTL::CThemeImpl<T>
    {
    public:
        CAeroBase(LPCWSTR lpstrThemeClassList = L"globals")
        {
            SetThemeClassList(lpstrThemeClassList);
        }
    
        bool IsTheming() const
        {
            return m_hTheme != 0;
        }
    
        template <class TCtrl>
        BOOL Subclass(TCtrl& Ctrl, INT idCtrl)
        {
            return aero::Subclass(Ctrl, 
                static_cast<T*>(this)->GetDlgItem(idCtrl));
        }
    
        bool DrawPartText(HDC dc, int iPartID, int iStateID,
            LPCTSTR pStr, LPRECT prText, UINT uFormat, DTTOPTS &dto)
        {
            HRESULT hr = S_FALSE;
            if(IsTheming())
                if (IsSupported())
                    hr = DrawThemeTextEx (dc, iPartID, iStateID,
                        pStr, -1, uFormat, prText, &dto );
                else
                    hr = DrawThemeText(dc, iPartID, iStateID, pStr, -1,
                        uFormat, 0, prText);
            else
                hr = CDCHandle(dc).DrawText(pStr, -1, prText, uFormat) != 0 ?
                     S_OK : S_FALSE;
    
            return SUCCEEDED(hr);
        }
    
         bool DrawPartText(HDC dc, int iPartID, int iStateID, LPCTSTR pStr,
            LPRECT prText, UINT uFormat,
            DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0)
        {
            DTTOPTS dto = {sizeof(DTTOPTS)};
            dto.dwFlags = dwFlags;
            dto.iGlowSize = iGlowSize;
            return DrawPartText(dc, iPartID, iStateID, pStr, prText, 
                                uFormat, dto);
        }
    
        bool DrawText(HDC dc, LPCTSTR pStr, LPRECT prText, UINT uFormat,
            DTTOPTS &dto)
        {
            return DrawPartText(dc, 1, 1, pStr, prText, uFormat, dto);
        }
    
        bool DrawText(HDC dc, LPCTSTR pStr, LPRECT prText, UINT uFormat,
            DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0)
        {
            return DrawPartText(dc, 1, 1, pStr, prText, uFormat, dwFlags,
                iGlowSize);
        }
    };
  • aero::CAeroImpl 派生自 CAeroBase WTL::CBufferedPaintImpl ,并通过其 m_Margins 成员管理半透明区域。
    SetMargins() 和各种 SetOpaque() 成员允许控制半透明区域。
    DoPaint() 成员由 CBufferedPaintImpl::OnPaint() 使用系统缓冲的 DC 调用。
    反过来,它会调用派生类的 Paint(CDCHandle dc, RECT& rClient, RECT& rView, RECT& rDest) ,其中 rClient 是 Windows 客户端矩形,rView 是边距内的区域,rDest 是绘制区域。

    /////////////////////////////////////////////////////////////////////
    // aero::CAeroImpl - implementation of Aero translucency (when available)
    
    template <class T>
    class CAeroImpl :
        public WTL::CBufferedPaintImpl<T>,
        public CAeroBase<T>
    {
    public:
        CAeroImpl(LPCWSTR lpstrThemeClassList = L"globals") :
            CAeroBase<T>(lpstrThemeClassList)
        {
            m_PaintParams.dwFlags = BPPF_ERASE;
            MARGINS m = {-1};
            m_Margins = m;
        }
    
        MARGINS m_Margins;
    
        bool SetMargins(MARGINS& m)
        {
            m_Margins = m;
            T* pT = static_cast<T*>(this);
            return pT->IsWindow() && IsComposing() ?
                SUCCEEDED(DwmExtendFrameIntoClientArea
                        (pT->m_hWnd, &m_Margins)) :
                true;
        }
    
        bool SetOpaque(bool bOpaque = true)
        {
            MARGINS m = {bOpaque - 1};
            return SetMargins(m);
        }
    
        bool SetOpaque(RECT &rOpaque)
        {
            T* pT = static_cast<T*>(this);
            RECT rClient;
            pT->GetClientRect(&rClient);
            MARGINS m = {rOpaque.left, rClient.right - rOpaque.right,
                rOpaque.top, rClient.bottom - rOpaque.bottom};
            return SetMargins(m);
        }
    
        bool SetOpaqueUnder(ATL::CWindow wChild)
        {
            T* pT = static_cast<T*>(this);
            ATLASSERT(wChild.IsWindow());
            ATLASSERT(pT->IsChild(wChild));
    
            RECT rChild;
            wChild.GetWindowRect(&rChild);
            pT->ScreenToClient(&rChild);
    
            return SetOpaque(rChild);
        }
    
        bool SetOpaqueUnder(UINT uID)
        {
            return SetOpaqueUnder(static_cast<T*>(this)->GetDlgItem(uID));
        }
    
    // implementation
        void DoPaint(CDCHandle dc, RECT& rDest)
        {
            T* pT = static_cast<T*>(this);
    
            RECT rClient;
            pT->GetClientRect(&rClient);
    
            RECT rView = {rClient.left + m_Margins.cxLeftWidth,
                rClient.top + m_Margins.cyTopHeight,
                rClient.right - m_Margins.cxRightWidth,
                rClient.bottom - m_Margins.cyBottomHeight};
    
            if (!IsComposing())
                if (IsTheming())
                    pT->DrawThemeBackground(dc, WP_FRAMEBOTTOM,
                    pT->m_hWnd == GetFocus() ? FS_ACTIVE : FS_INACTIVE,
                    &rClient, &rDest);
                else
                    dc.FillSolidRect(&rClient, ::GetSysColor(COLOR_MENUBAR));
    
            if ((m_Margins.cxLeftWidth != -1) && !::IsRectEmpty(&rView))
            {
                dc.FillSolidRect(&rView, ::GetSysColor(COLOR_WINDOW));
                if (!m_BufferedPaint.IsNull())
                    m_BufferedPaint.MakeOpaque(&rView);
            }
            else
                ::SetRectEmpty(&rView);
    
            pT->Paint(dc, rClient, rView, rDest);
        }
    
        // Overrideables
        void Paint(CDCHandle /*dc*/, RECT& /*rClient*/,
            RECT& /*rView*/, RECT& /*rDest*/)
        {}
    
        void OnComposition()
        {}
    
        void OnColorization()
        {}
    
        BEGIN_MSG_MAP(CAeroImpl)
            CHAIN_MSG_MAP(CThemeImpl<T>)
            MESSAGE_HANDLER(WM_CREATE, OnCreate)
            MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
            MESSAGE_HANDLER(WM_DWMCOMPOSITIONCHANGED, OnCompositionChanged)
            MESSAGE_HANDLER(WM_DWMCOLORIZATIONCOLORCHANGED, 
                            OnColorizationChanged)
            CHAIN_MSG_MAP(CBufferedPaintImpl<T>)
        END_MSG_MAP()
    
        LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/,
            LPARAM /*lParam*/, BOOL& bHandled)
        {
            if (IsThemingSupported())
                OpenThemeData();
    
            if (IsComposing())
                ::DwmExtendFrameIntoClientArea(static_cast<T*>(this)->m_hWnd,
                &m_Margins);
            return bHandled = FALSE;
        }
    
        LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/,
            LPARAM /*lParam*/, BOOL& bHandled)
        {
            if (!IsComposing() && IsTheming())
                static_cast<T*>(this)->Invalidate(FALSE);
            return bHandled = FALSE;
        }
    
        LRESULT OnCompositionChanged(UINT /*uMsg*/, WPARAM /*wParam*/,
            LPARAM /*lParam*/, BOOL& bHandled)
        {
            if (IsComposing())
                SetMargins(m_Margins);
            static_cast<T*>(this)->OnComposition();
            return bHandled = FALSE;
        }
    
        LRESULT OnColorizationChanged(UINT /*uMsg*/, WPARAM /*wParam*/,
            LPARAM /*lParam*/, BOOL& bHandled)
        {
            static_cast<T*>(this)->OnColorization();
            return bHandled = FALSE;
        }
    };
    

适配器类

这些类将 aero 玻璃效果应用于现有控件。

  • aero::CCtrl 用于对系统和通用控件进行子类化。
    有两个成员用于专门化:GetThemeName() 返回控件的主题名称,用于在创建或子类化时打开,CtrlPaint(HDC hdc, RECT& rCtrl, RECT& rPaint) 通过重写的 OnBufferedPaint() 成员进行绘图时调用。
    三个 DrawCtrlxxx() 成员是专门绘图例程的辅助函数。
    AERO_CONTROL() 宏有助于一步声明和子类化子控件。

    //////////////////////////////////////////////////////////////////////////
    // aero::CCtrl -  implementation of Aero drawing for system controls
    // Note: This class is intended for system themed control specializations
    
    template<class TBase>
    class CCtrl :
        public WTL::CBufferedPaintWindowImpl<CCtrl<TBase>, TBase>,
        public CAeroBase<CCtrl<TBase> >
    {
    public:
    
        typedef CAeroBase<CCtrl<TBase> > baseAero;
        typedef WTL::CBufferedPaintWindowImpl<CCtrl<TBase>, TBase> baseWindow;
    
        DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
    
        // creation and initialization
        CCtrl(LPCWSTR lpstrThemeClassList = GetThemeName()) :
            baseAero(lpstrThemeClassList)
        {
            m_PaintParams.dwFlags = BPPF_ERASE;
        }
    
        CCtrl<TBase>& operator =(HWND hWnd)
        {
            TBase::m_hWnd = hWnd;
            return *this;
        }
    
        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)
        {
            TBase baseCtrl;
            if (baseCtrl.Create(hWndParent, rect.m_lpRect,
                szWindowName, dwStyle, dwExStyle, 
                        MenuOrID.m_hMenu, lpCreateParam)
                != NULL)
                SubclassWindow(baseCtrl.m_hWnd);
            return m_hWnd;
        }
    
        BOOL SubclassWindow(HWND hWnd)
        {
            ATLASSERT(IsSupported());
            if(baseWindow::SubclassWindow(hWnd))
                OpenThemeData();
            return m_hWnd != NULL;
        }
    
        // specializables
        static LPCWSTR GetThemeName()
        {
            return TBase::GetWndClassName();
        }
    
        void CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint)
        {
            DefCtrlPaint(hdc, rPaint);
        }
    
        // operations
        void DefCtrlPaint(HDC hdc, RECT& rPaint, bool bEraseBkGnd = false)
        {
            if (bEraseBkGnd)
                DefWindowProc(WM_ERASEBKGND, (WPARAM)hdc, NULL);
            DefWindowProc(WM_PAINT, (WPARAM)hdc, 0);
            m_BufferedPaint.MakeOpaque(&rPaint);
        }
    
        BOOL DrawCtrlBackground(HDC hdc, int nPartID, int nStateID,
            RECT &rCtrl, RECT &rPaint)
        {
            return SUCCEEDED(DrawThemeBackground(hdc, nPartID, nStateID,
                &rCtrl, &rPaint));
        }
    
        BOOL DrawCtrlEdge(HDC hdc, int nPartID, int nStateID, RECT &rCtrl,
            UINT uEdge = EDGE_ETCHED, UINT uFlags = BF_RECT,
            LPRECT pContentRect = NULL)
        {
            return SUCCEEDED(DrawThemeEdge(hdc, nPartID, nStateID, &rCtrl,
                uEdge, uFlags, pContentRect));
        }
    
        BOOL DrawCtrlText(CDCHandle dc, int nPartID, int nStateID, 
            UINT uFormat, RECT &rCtrl, HFONT hFont = 0,
            DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0)
        {
            HRESULT hr;
            RECT rText;
            hr = GetThemeBackgroundContentRect
            (dc, nPartID, nStateID, &rCtrl, &rText);
            MARGINS m = {0};
            hr = GetThemeMargins(dc, nPartID, nStateID, TMT_CONTENTMARGINS,
                &rText, &m);
            rText.left += m.cxLeftWidth;
            rText.right -= m.cxRightWidth;
            int iLength = GetWindowTextLength();
            if (iLength > 0)
            {
                CTempBuffer<wchar /> sText(++iLength);
                GetWindowText(sText, iLength);
    
                HFONT hf = dc.SelectFont(hFont == 0 ? GetFont() : hFont);
                hr = DrawPartText(dc, nPartID, nStateID, sText,  &rText ,
                    uFormat, dwFlags, iGlowSize);
                dc.SelectFont(hf);
            }
            return SUCCEEDED(hr) && iLength > 0;
        }
    
        // implementation
        void DoBufferedPaint(HDC hdc, RECT& rPaint)
        {
            HDC hDCPaint = NULL;
            RECT rCtrl;
            GetClientRect(&rCtrl);
            m_BufferedPaint.Begin(hdc, &rCtrl, m_dwFormat, &m_PaintParams,
                &hDCPaint);
            ATLASSERT(hDCPaint != NULL);
            CtrlPaint(hDCPaint, rCtrl, rPaint);
            m_BufferedPaint.End();
        }
    
        void DoPaint(HDC /*hdc*/, RECT& /*rCtrl*/)
        {
            DefWindowProc();
        }
    
        BEGIN_MSG_MAP(CCtrl)
            MESSAGE_HANDLER(WM_PAINT, OnPaintMsg)
            MESSAGE_HANDLER(WM_ERASEBKGND, OnPaintMsg)
            CHAIN_MSG_MAP(baseAero)
            CHAIN_MSG_MAP(baseWindow)
        END_MSG_MAP()
    
        LRESULT OnPaintMsg(UINT /*uMsg*/, WPARAM /*wParam*/, 
        LPARAM /*lParam*/, BOOL& bHandled)
        {
            if(!IsComposing())
                return DefWindowProc();
            else
                return bHandled = FALSE;
        }
    };
    
    /////////////////////////////////////////////////////////////////////////
    // Macro declaring and subclassing a control
    // (static declaration to use in OnCreate or OnInitDialog members)
    
    #define AERO_CONTROL(type, name, id)\
        static aero::type name;\
        Subclass(name, id);
    

  • aero::CCtrlImpl 在现有 TCtrlImpl 之上启用 Aero 绘图。DoPaint() 成员可以在派生类中重写以调用 TCtrlImpl 相关代码。

    //////////////////////////////////////////////////////////////////////////
    // aero::CCtrlImpl -  implementation of Aero drawing for user and WTL 
    // defined controls
    // Note: This class is intended for derivation
    
    template <class T, class TCtrlImpl, bool t_bOpaque = false>
    class ATL_NO_VTABLE CCtrlImpl :
        public TCtrlImpl,
        public CAeroImpl<T>
    {
    public:
        DECLARE_WND_SUPERCLASS(NULL, TCtrlImpl::GetWndClassName())
    
        CCtrlImpl(LPCWSTR lpstrThemeClassList = L"window") : 
                            CAeroImpl(lpstrThemeClassList)
        {
            m_PaintParams.dwFlags = BPPF_ERASE;
        }
    
        void DoPaint(HDC hdc, RECT& rect)
        {
            BOOL bHandled = TRUE;
            TCtrlImpl::OnPaint(WM_PAINT, (WPARAM) hdc, NULL, bHandled);
            if (t_bOpaque)
                m_BufferedPaint.MakeOpaque(&rect);
        }
    
        BEGIN_MSG_MAP(CCtrlImpl)
            CHAIN_MSG_MAP(CAeroImpl<T>)
            CHAIN_MSG_MAP(TCtrlImpl)
        END_MSG_MAP()
    
    };
    

替换类

这些是启用 Aero 的类,它们替换了具有相同名称的 WTL:: ATL:: 类。它们用于第一部分的入门指南。

可派生类:这些类派生自 aero::CAeroImpl

  • aero::CWindowImpl< T, TBase, TWinTraits >
  • aero::CDialogImpl<T, TBase>
  • aero::CFrameWindowImpl<T, TBase, TWinTraits>
  • aero::CPropertySheetImpl<T, TBase>
  • aero::CPropertyPageImpl<T, TBase>
  • aero::CSplitterImpl<T, t_bVertical>
  • aero::CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
  • aero::CSplitterWindowT<t_bVertical>

aero::CCtrl 派生或专门化的类

  • aero::CEdit
  • aero::CTabCtrl
  • aero::CToolBarCtrl
  • aero::CStatusBarCtrl
  • aero::CListBox
  • aero::CComboBox
  • aero::CStatic
  • aero::CButton

aero::CCtrlImpl 派生的类

  • aero::CCommandBarCtrl
  • aero::CTabView
  • aero::CPaneContainer
  • aero::CPrintPreviewWindow

结论

在现有的原生代码应用程序中启用漂亮的 Aero 玻璃效果并非难事。干杯!

修订历史

  • 2007 年 5 月 31 日发布
  • 2007 年 6 月 5 日 修复了 aero::CTabView 和示例通用 CAeroView 中的向后兼容性问题,并调整了文章
© . All rights reserved.