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

一些能让您的 ATL/WTL 程序拥有更好外观的 Mix-in 类

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.69/5 (5投票s)

2004年4月2日

6分钟阅读

viewsIcon

54839

downloadIcon

1042

本文介绍了一些用于 WTL 的 Mix-In 类。这些 Mix-In 类提供了 WTL/ATL 框架不支持的一些功能,例如拥有绘制菜单、皮肤化对话框按钮和静态文本控件。

Sample Image - maindlg.gif

目录

引言

我是一名 MFC 程序员,MFC 是一个很好的框架。但 MFC 在计划和开发小型内存驻留程序方面也有一些缺点。对于这类程序,我们需要程序体积小、占用资源少且没有资源泄漏。显然,这不是 MFC 的优势,所以我开始研究 WTL。与 MFC 不同,WTL 没有内置支持拥有绘制菜单。我编写了 CMenuHelp 类来为普通的 WTL 窗口提供菜单皮肤功能。CWzButtonImpl 是一个简单的拥有绘制按钮类,它与 CButtonHelp 配合,后者使用 CWzButtonImpl 来子类化对话框中的所有按钮。CButtonHelp 也可以与其他拥有绘制按钮类配合。CCtrlColor 处理对话框窗口的 WM_CTLCOLORDLGWM_CTLCOLORSTATIC 消息,使用模板参数更改对话框的背景色和控件的文本颜色。

由于我不是 WTL/ATL 框架的专家,不能保证代码对每个人都有效。欢迎任何建议。您可能会注意到本文档存在许多语法错误,甚至有时完全错误,这是因为我不是英语母语者。希望大家都能理解这篇文章。

CMenuHelp

众所周知,当菜单弹出时,Windows 系统会向菜单的所有者窗口发送 WM_INITMENUWM_ENTERMENULOOP 消息,当菜单消失时,Windows 系统会向所有者窗口发送 WM_EXITMENULOOP 消息。如果菜单项具有 MFT_OWNERDRAW 属性,Windows 还会发送 WM_MEASUREITEM 来测量菜单项,并发送 WM_DRAWITEM 消息让所有者窗口绘制菜单项。

CMenuHelp 是一个模板类,也是一个 MixIn 类。它处理所有者窗口的 5 个消息。在 WM_INITMENU 消息处理中,它获取活动菜单的句柄(菜单尚未显示)并调用 AttachActiveMenu() 为该菜单中的所有菜单项添加 MFT_OWNERDRAW 属性。当菜单消失时,会调用 DetachActiveMenu(),此方法会移除 AttachActiveMenu() 添加的 MFT_OWNERDRAW 属性。

CMenuHelp 的属性

  • HMENU CMenuHelp::m_hActiveMenu

    存储弹出菜单的句柄,OnMeasureItemOnDrawItem 使用此句柄对弹出菜单执行某些操作。

  • COLORREF CMenuHelp::m_crText

    用于绘制普通菜单项文本的颜色。

    COLORREF CMenuHelp::m_crHiText

    用于绘制选中菜单项文本的颜色。

  • COLORREF CMenuHelp::m_crBkGnd

    用于绘制菜单项背景的颜色。

  • COLORREF CMenuHelp::m_crHiBkGnd

    用于绘制选中菜单项背景的颜色。

CMenuHelp 的方法

  • HMENU CMenuHelp::AttachActiveMenu(HMENU hActiveMenu)

    将将要弹出的菜单句柄附加到 m_hActiveMenuhActiveMenu 是新菜单的句柄。AttachActiveMenu() 为该菜单中的所有菜单项添加 MFT_OWNERDRAW 属性,因此系统会向我们的窗口发送 WM_MEASUREITEMWM_DRAWITEM 消息。CMenuHelp 处理这两个消息来绘制菜单。AttachActiveMenu() 返回上一个弹出菜单的句柄。

  • HMENU CMenuHelp::DetachActiveMenu()

    m_hActiveMenu 的所有菜单项中移除 MFT_OWNERDRAW 属性并将 m_hActiveMenu 设置为 NULL。它返回当前弹出菜单的句柄。

在您的代码中使用 CMenuHelp

在代码中使用此类非常简单。将 MenuHelp.h 包含到您的项目中,将 CMenuHelp 添加到您窗口的派生链中,如下所示:

  class CMainDlg : public CDialogImpl<CMainDlg>,public CMenuHelp<CMainDlg>

最后,将声明信息添加到消息链中:

BEGIN_MSG_MAP(CMainDlg)
    ...
    CHAIN_MSG_MAP(CMenuHelp<CMainDlg>)
    ...
END_MSG_MAP()

当它工作时,该窗口的所有弹出菜单都将由我们的 CMenuHelp 绘制,而不是 Windows 的普通菜单外观。

CButtonHelp

CButtonHelp 是一个用于更改对话框中按钮控件外观的辅助类。它在对话框初始化自身时修改并将 BS_OWNERDRAW 属性添加到所有推送按钮,并将这些按钮控件链接到 CWzButtonImpl 类。CWzButtonImpl 是真正的拥有绘制按钮类。CWzButtonImpl 使用 SubclassWindow 来接管标准 Windows 按钮的测量和绘制行为,就像大多数其他 MFC 的 CButton 派生类一样。

CWzButtonImpl

CWzButtonImpl 是一个派生自 CButton (ATL 类) 的拥有绘制按钮类。它易于使用,就像大多数 MFC 的拥有绘制按钮类一样。首先声明一个 CWzButtonImpl 对象,然后调用 SubclassWindow 方法将其附加到推送按钮控件。如果您不喜欢当前的样式,可以在此类中修改绘制代码来更改按钮控件的外观。您也可以用其他拥有绘制按钮类替换此类。您可以在 CodeProject 中找到很多。您也可以在应用程序中指定几种不同的拥有绘制按钮类(样式),但一个对话框中只能使用一个类。

CButtonHelp 的属性

  • CSimpleArray<t_ButtonClass *> CButtonHelp::m_arButtons

    存储对话框中的所有 t_ButtonClass 对象,每个 t_ButtonClass 对象都附加到一个推送按钮。t_ButtonClass 是一个模板参数,在我们的示例代码中应为 CWzButtonImpl

CButtonHelp 的方法

  • BOOL CButtonHelp::SubclassAllButtons()

    将对话框中的推送按钮附加到 t_ButtonClass 类对象。通常在窗口的初始化函数中调用,例如 CDialog::OnInitDialog

  • BOOL CButtonHelp::SubclassButton(HWND hBtnWnd)

    创建一个 t_ButtonClass 对象并将其附加到普通推送按钮控件。hBtnWnd 是按钮控件的 HWND

  • BOOL CButtonHelp::UnSubclassButton(HWND hBtnWnd)

    从推送按钮控件分离 t_ButtonClass 对象。hBtnWnd 是按钮控件的 HWNDt_ButtonClass 对象将被从 CMenuHelp::m_arButtons 中删除。

  • int CButtonHelp::FindButtons(HWND hBtnWnd)

    用于确定一个推送按钮控件是否已经被子类化。

在您的代码中使用 CButtonHelp

首先将 ButtonHelp.h 包含到您的项目中,然后将 CButtonHelp 类添加到对话框的派生链中,如下所示:

class CMainDlg : public CDialogImpl<CMainDlg>, 
    public CButtonHelp<CMainDlg,CWzButtonImpl>

最后,别忘了在 CDialog::OnInitDialog 中调用 SubclassAllButtons()

CCtrlColor

CCtrlColor 类处理一些 WM_CTLCOLOR* 消息(目前仅支持 WM_CTLCOLORDLGWM_CTLCOLORSTATIC),并使用特殊的文本颜色和背景颜色(由模板参数指定)绘制对话框中的控件。这是一个非常简单的类,只有 34 行 C++ 代码。

CCtrlColor 的属性

  • HBRUSH CCtrlColor::m_brBkgnd

    HBRUSH GDI 对象:CCtrlColor 类使用此画笔绘制对话框和控件的背景。CCtrlColor 在构造函数中创建此对象,使用模板参数 t_crBkgnd 指定的颜色,并在析构函数中删除此对象。

在您的代码中使用 CCtrlColor

CCtrlColor 有三个模板参数:Tt_crTextColort_crBkgnd。后两个是可选的,它们默认为 RGB(64,64,255) 和 RGB(222,222,222)。因此,您可以通过两种方法将 CCtrlColor 添加到对话框的派生链中:

class CMainDlg : public CDialogImpl<CMainDlg>, public CCtrlColor<CMainDlg>

class CAboutDlg : public CDialogImpl<CAboutDlg>, 
    public CCtrlColor<CAboutDlg,RGB(64,128,64)>

CMenuHelp 相同,将声明信息添加到消息链中:

BEGIN_MSG_MAP(CMainDlg)
    ...
    CHAIN_MSG_MAP(CCtrlColor<CMainDlg>)
    ...
END_MSG_MAP()

    关于演示代码

    所有源代码都组织在一个 VC6 项目中,未在 VC7 编译器中测试。由于本文档讨论的是 ATL/ATL,您还应该安装 WTL 来编译源代码。此代码的使用没有限制,可用于任何目的。

    © . All rights reserved.