WTL for MFC Programming实践篇 --- 一个自定义ComboBox的移植过程(下)

原创 2004年08月03日 13:46:00
 

《程序员修炼之道》说当你想说这不可能的时候,往往是你在调用的方法上出现了错误。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

我们重新回到起点,来看看那里出了错。仔细地研读代码以后发现,事件是怎么传递到MSG_MAP的呢?难道我们通过赋值将一个窗体句柄传进来,我们在这个类中定义的MSG_MAP就能自动的连接到这个句柄上吗?这显然是真的不可能。

那么没有将MSG_MAP连接到窗体句柄很可能是控件类无法收到任何事件的原因。那么如何将MSG_MAP连接到窗体句柄上呢?原书中提到一个重要的函数,CWindowImpl::SubclassWindow()。我们再次更改我们的控件类:

     CComboBoxEx& operator =(HWND hWnd) {

         CWindowImpl< CComboBoxEx, CComboBox>::SubclassWindow(hWnd);

         return *this;

     }

     一测之下,大吃一惊。不仅重画事件被正确触发,连析构函数中的没有AttachDetach这个怪用法也可以删除了。为什么会这样呢?探究这个问题之前,让我们先看看原书使用的DDX_CONTROL - 它只针对CWindowImpl的派生类起作用 - 是怎么回事。原码如下:

     #define DDX_CONTROL(nID, obj) /

         if(nCtlID == (UINT)-1 || nCtlID == nID) /

              DDX_Control(nID, obj, bSaveAndValidate);

 

     // Full control subclassing (for CWindowImpl derived controls)

template <class TControl>

     void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)

     {

         if(!bSave && ctrl.m_hWnd == NULL)

         {

              T* pT = static_cast<T*>(this);

              ctrl.SubclassWindow(pT->GetDlgItem(nID));

         }

     }

     从原码可以看到,DDX_CONTROL宏和DDX_CONTROL_HANDLER宏实现的区别只是,前者使用SubclassWindow,而后者使用操作符“=”。如果把我们上面的代码联系起来,在操作符“=”的处理函数中调用SubclassWindow,其实就等于是明着使用DDX_CONTROL_HANDLER宏,暗地里却把DDX_CONTROL宏实现了。原来想出门,结果先绕着后院跑了3圈,这真是一个大笑话。

     为什么会这样呢?不使用DDX_CONTROL宏是因为CComboBox没有SubclassWindow函数,而是用CComboBox是因为在MFCCComboBoxEx就是从CComboBox派生,移植的时候当然倾向于选择同名的类,而不是CWindowImpl<CComboBoxEx, CComboBox>这样怪怪的声明方法。

     可是这里忽视了一个基本的WTL特性,由于WTL基于ATL,而设计ATL就是为了将接口和实现分开,所以在WTL中所有不带Impl字样的类都不是实现类,像CWindowCButtonCComboBox等等,他们只是包含一个句柄,没有自己的事件,他们只是负责中转,封装控件事件等等。像CComboBox的操作符“=”就只是一个赋值语句而已。而DDX_CONTROL_HANDLER正是为这些类服务的,当然如果我们注意到这个宏得注释,也许早就发现这个问题了,还记得吗?在这里重温一下吧:

     // Full control subclassing (for CWindowImpl derived controls)

template <class TControl>

     void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)

 

// Simple control attaching (for HWND wrapper controls)

     template <class TControl>

     void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)

 

     好了,在环游地球一周以后,我们又回到了起点,虽然费了不少的力气,但也搞清楚不少的东西,下面大概地总结一下:

1.      WTL的类包含接口类(只包含窗体句柄和事件的封装)和实现类(可以拥有自己的事件),要根据具体情况有选择的使用。

2.      WTL不会自动销毁窗体句柄(当然是指接口类),所以Attach操作以后要记着Detach

3.      注意包含有HANDLE的宏,类,函数,它们往往是接口类或为接口类服务的,如上面所说的DDX_Control_Handle,以及CDCHandle等等。

4.      DDX是通过宏定义重载CWinDataExchange::DoDataExchange()函数实现的

5.      消息反射是在取道发送消息的窗体句柄后,通过像它回发相应的消息来实现的。

6.      当你想说这不可能的时候,往往是你在调用的方法上出现了错误。

7.      多看看代码,你会了解得更多。

Combobox的简单自绘实现

#pragma once class CCustomComboBox:public CComboBox{ DECLARE_MESSAGE_MAP(); DECLARE_DYNAMIC(CCust...
  • tianminghahaha
  • tianminghahaha
  • 2016年04月28日 14:39
  • 2365

ffplay播放器移植VC的工程:ffplay for MFC

ffplay播放器移植VC的工程:ffplayfor MFC本文介绍一个自己做的FFPLAY移植到VC下的开源工程:ffplayfor MFC。本工程将ffmpeg项目中的ffplay播放器(ffpl...
  • leixiaohua1020
  • leixiaohua1020
  • 2014年06月06日 00:07
  • 26737

VC++界面编程之--自定义CButton(按钮)皮肤

在VC++ WTL编程中,利用CustomDraw自绘的方法,可以很轻松地实现按钮的自绘效果。 我利用了此方法,制作了一个CCustomButton类,实现了如下效果的控件,其支持普通的按钮风格,并也...
  • renstarone
  • renstarone
  • 2013年09月05日 20:42
  • 6264

[ATL/WTL]_[初级]_[Win32窗口自定义消息处理过程]

场景 有时候我们需要单独对某个窗口消息进行拦截,比如CEdit响应回车, 这时候就需要拦截窗口处理过程了. 当然MFC的界面可以重载: BOOL CXXXDlg::PreTranslateMessag...
  • infoworld
  • infoworld
  • 2016年06月28日 16:50
  • 2792

使用IDA定位基于MFC的CrackMe的按钮函数-----实践篇(二)

接下来我将介绍另外两种方法来定位
  • SilverMagic
  • SilverMagic
  • 2014年10月30日 18:00
  • 936

duilib篇 如何在WTL和MFC中使用duilib及如何静态使用duilib库!(初级讲解 附带一个Demo)

关于duilib的历史,我也就不多说了,能看到这篇文章的人都是有一定了解才能找到这个的。 我直接说下对这个库的基本使用吧。   下载地址: http://download.csdn.net/d...
  • mail_cm
  • mail_cm
  • 2012年04月13日 15:25
  • 1537

测试驱动开发(Test-Driven Development,TDD)是通过测试定义所要开发的功能的接口,然后实现功能的开发过程。它是Extreme Programming (XP)--极限编程的一个重要组成部分

  • 2009年11月02日 09:39
  • 102KB
  • 下载

MFC自定义控件编写过程

  • 2014年01月07日 17:59
  • 37KB
  • 下载

一个基于MFC的简单的自定义背景和文本颜色的文本框[CMyEdit]控件

  • 2017年04月19日 00:26
  • 132KB
  • 下载

一个MFC的自定义按钮类

  • 2012年11月29日 11:17
  • 8KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WTL for MFC Programming实践篇 --- 一个自定义ComboBox的移植过程(下)
举报原因:
原因补充:

(最多只允许输入30个字)