本文的目的是使用ATL/WTL做一个与“创建有个性的对话框之MFC篇”的个性对话框一样的对话框。 ATL/WTL一套模板库,创建ATL/WTL应用程序不可避免的要用到C++的模板与多继承方面的知识,在看本文之前希望您对它们有所了解。本文结尾可 以下载文中介绍的例子代码,编译这些代码需要安装WTL库,对于WTL的更详细的信息请查看oRbIt翻译的“WTL for MFC Programmers”系列文章,具体位置在:
http://blog.csdn.net/orbit
。 ATL和WTL一起构建了一个轻量级的应用程序框架,ATL在设计时接口定义和实现是严格区分开的,这在窗口类的设计中是最明显的,这一点类似于COM, COM的接口定义和实现是完全分开的(或者可能有多个实现)。ATL有一个专门为窗口设计的接口,可以做全部的窗口操作,这就是CWindow。它实际上 就是对HWND操作的包装类,对几乎所有以HWND句柄为第一个参数的窗口API的进行了封装,例如:SetWindowText() 和 DestroyWindow()。在ATL类中对窗口过程的实现是CWindowImpl。CWindowImpl 含有所有窗口实现代码,例如:窗口类的注册,窗口的子类化,消息映射以及基本的WindowProc()函数,可以看出这与MFC的设计有很大的不同, MFC将所有的代码都放在一个CWnd类中。 由于ATL和MFC都是应用于Windows平台的库,所以他们都能够响应和处理系统发送的窗口消息,只是ATL和MFC对消息的分派方式不同,从而造成 编写代码方面的差异。这些差异并不是不可逾越,ATL也定义了一些与MFC类似的宏来处理和分派消息,每个ATL的窗口类都用一个消息映射表或者称其为消 息映射链,将消息处理函数与特定的消息关联起来,这和MFC的做法是类似的。少量的不同之处在于消息响应函数的参数,MFC对Windows的消息参数, 也就是wParam和lParam进行了内部解释,传递给消息响应函数的参数比较友好,ATL的消息响应函数则是原原本本的将wParam和lParam 传递给了消息响应函数,对Windows的消息不太熟悉的程序员可能会很迷惑。如果你对C++的模板机制比较了解,并且愿意不停的查阅MSDN,那就很容 易将MFC的窗口类“翻译”成ATL/WTL的窗口类,比如本文用到的CWzButtonImpl类就是从本文的“MFC姊妹篇”中例子代码的 CSMButton类翻译过来的。 在开始用ATL/WTL创建个性对话框之前,还要介绍一下ATL中常用的嵌入类(Mix-in class)。ATL的另一个显著不同之处就是任何一个C++类都可以响应消息,而MFC只是将消息响应任务分给了CWnd类和CCmdTarget类, 外加几个有PreTranslateMessage()方法的类。ATL的这种特性允许我们编写所谓的“嵌入类”,为我们的窗口添加特性只需将该类添加到 继承列表中就行了,就这么简单!一个基本的带有消息映射链的类通常是模板类,将派生类的类名作为模板的参数,这样它就可以访问派生类中的成员,比如 m_hWnd(CWindow类中的HWND成员)。让我们来看一个嵌入类的例子,这个嵌入类通过响应WM_ERASEBKGND消息来画窗口的背景: template <class T, COLORREF t_crBrushColor> BEGIN_MSG_MAP(CPaintBkgnd) protected: 让 我们来研究一下这个新类。首先,CPaintBkgnd有两个模板参数:使用CPaintBkgnd的派生类的名字和用来画窗口背景的颜色。(t_ 前缀通常用来作为模板类的模板参数的前缀)CPaintBkgnd也是从CMessageMap派生的,这并不是必须的,因为所有需要响应消息的类只需使 用BEGIN_MSG_MAP宏就足够了,所以你可能看到其他的一些嵌入类的例子代码,它们并不是从该基类派生的。 class CMyWindow : public CWindowImpl<CMyWindow, CWindow, CFrameWinTraits>, 其次,需要CMyWindow将消息传递给CPaintBkgnd,就是将其链入到消息映射链,在CMyWindow的消息映射链中加入CHAIN_MSG_MAP宏: typedef CPaintBkgnd<CMyWindow, RGB(0,0,255)> CPaintBkgndBase; BEGIN_MSG_MAP(CMyWindow) 任 何CMyWindow没有处理的消息都被传递给CPaintBkgnd。应该注意的是WM_CLOSE,WM_DESTROY和IDC_ABOUT消息将 不会传递,因为这些消息一旦被处理消息映射链的查找就会中止。你可以在继承列表中使用多个嵌入类,每一个嵌入类使用一个CHAIN_MSG_MAP宏,这 样消息映射链就会将消息传递给它。这与MFC不同,MFC的CWnd派生类只能有一个基类,MFC自动将消息传递给基类。 class CMainDlg : public CDialogImpl<CMainDlg>, 这样CMainDlg就拥有了蓝色的背景,改变CPaintBkgnd的模板参数t_crBrushColor可以定制对话框不同的颜色,下面的代码使得对话框拥有了淡绿色的背景: class CMainDlg : public CDialogImpl<CMainDlg>, 和在MFC中处理WM_ERASEBKGND消息一样,控件的背景颜色还没有改变,下面本文就介绍在ATL/WTL框架下如何响应WM_CTLCOLORXXX消息。 下面就是使用了CCtrlColor之后的效果图,这里没有继续使用CPaintBkgnd,因为CCtrlColor中处理了WM_CTLCOLORDLG通知消息。 在对话框中使用位图背景也很简单,只要照着CPaintBkgnd样子写一个画位图的类就行了,以下是一个简单的例子: template <class T, UINT uBitmapID> BEGIN_MSG_MAP(CPaintBkgnd) protected: 和CPaintBkgnd 相比,CBitmapBkgnd只是修改了第二个模板参数和OnEraseBkgnd()函数的代码,由于使用位图作为对话框的背景,对话框中的控件在处 理WM_CTLCOLORXXX系列消息时应该返回一个空画刷而不是默认的背景颜色画刷,也就是需要一个定制的处理WM_CTLCOLORXXX系列消息 的嵌入类,本文用了CCtrlHollowColor与CBitmapBkgnd配合使用,但是CCtrlHollowColor过于简单,它只能在本文 的例子中使用,如果对话框中有更多的控件就需要修改CCtrlHollowColor类的代码。 现在该考虑按钮的问题了,和本文的MFC姊妹篇一样,本文设计的WTL例子也使用了一个自画按钮类。前文已经提过,它其实就是从CSMButton“移 植”过来的,你肯定觉得还是有些不一样,那是因为CWzButtonImpl使用了ATL的特性,那就是使用WTL的嵌入类:COwnerDraw。在 MFC的按钮类CSMButton中,WM_DRAWITEM消息被MFC做了内部映射,最终的按钮绘制映工作交给了虚函数DrawItem(),这是利 用了C++的多态机制。ATL/WTL不使用虚函数,多继承和嵌入类是它拥有比MFC更加灵活的方式避开了使用虚函数,这也就使得ATL/WTL的窗口对 象比MFC的窗口对象占用更少的内存。只要将COwnerDraw类加入窗口类的集成列表,就可以原封不动的将CSMButton::DrawItem ()搬到CWzButtonImpl中,以下是CWzButtonImpl类的完整声明,可以看到它是个窗口类,具有CButton的接口: class CWzButtonImpl : public CWindowImpl<CWzButtonImpl, CButton>,public COwnerDraw<CWzButtonImpl> CWzButtonImpl的使用方法可在ATL中与MFC有较大的差异,它只能通过SubclassWindow()这个方法与控件关联起来,不过有了WTL之后就和MFC一样了,因为ATL也实现了类似MFC的DDE/DDV。 template <class T, class t_ButtonClass> 第一个模板参数是窗口类,第二个模板参数就是按钮类,通过替换模板参数t_ButtonClass可以在不同的对话框中使用不同风格的按钮,下面的例子就是本文使用的例子代码中主对话框的声明,他使用CWzButtonImpl来子类化按钮控件: class CMainDlg : public CDialogImpl<CMainDlg>, public CCtrlColor<CMainDlg>, 假设还有一个自画按钮类CBitmapButtonImpl,下面的声明将使CBmpDlg对话框拥有了另一种风格的自画按钮: class CBmpDlg : public CDialogImpl<CBmpDlg>, public CCtrlColor<CBmpDlg>, CButtonHelp 类有三个主要的函数,一个是SubclassAllButtons(),这个函数遍历对话框所有的子控件,子类化其中具有pushbutton风格的按 钮,SubclassButton()子类化指定的按钮,UnSubclassButton()则是SubclassButton()的逆过程。
|
创建有个性的对话框之ATL/WTL篇
最新推荐文章于 2024-09-10 13:48:42 发布