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

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.04/5 (10投票s)

2004年4月12日

CPOL

6分钟阅读

viewsIcon

73461

downloadIcon

1462

本文讨论了一些用于 WTL 的 MixIn 类。这些 MixIn 类提供了 WTL/ATL 框架不支持的某些功能,例如所有者绘制菜单、换肤的对话框按钮和静态文本控件。

目录

引言

我用 MFC 已经很长时间了,它是一个非常好的框架。但 MFC 也有一些缺点,尤其是在计划和开发小型内存驻留程序方面。对于这类程序,我们希望程序体积小,占用资源少,并且没有资源泄漏。显然,这并不是 MFC 的优势,所以我开始研究 WTL。与 MFC 不同,WTL 没有内置对所有者绘制菜单的支持。我编写了 CMenuHelp 类,用于普通的 WTL 窗口来换肤窗口的弹出菜单。CWzButtonImpl 是一个简单的所有者绘制按钮类,它与 CButtonHelp 配合使用,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/WTL,您还应该安装 WTL 来编译源代码。此代码的使用没有任何限制,可以用于任何目的。

© . All rights reserved.