最近转做服务端开发,或多或少有点坑爹的感觉。目前正在恶补Linux C/C++编程,主要还是集中在Linux系统API的学习。不过也好,以后更新的内容不仅仅只有Windows了。

今天说一点简单的东西,还是MFC的。不知道有多少人用过BEGIN_TEMPLATE_MESSAGE_MAP,没用过的可以看看,用过的请绕道。

关于message map,这里不打算深入介绍。想要深入了解的看侯捷同学写的《深入浅出MFC》。

MFC Message Map相关的点主要是下面两个:

    • DECLARE_MESSAGE_MAP()
    • BEGIN_MESSAGE_MAP(theClass, baseClass)
    • END_MESSAGE_MAP()
    • ON_WM_XXXXX()
  • 数据结构
    • struct AFX_MSGMAP
    • struct AFX_MSGMAP_ENTRY

这里就说一说宏。

我们把这些宏展开就知道MFC利用这些宏到底做了些什么事情。这些宏其实就是声明和定义了一个虚函数和一个静态成员函数。在这个静态函数的定义里我们还可以看到一个静态类型的数组。把这些宏展开,大致看到的就是这样一副场景。注:MFC在message map上使用到的技巧还是很值得学习和借鉴的。

// theClass.h
protected:
static const AFX_MSGMAP* __stdcall GetThisMessageMap();
virtual const AFX_MSGMAP* GetMessageMap() const;
// theClass.cpp
// BEGIN_MESSAGE_MAP(theClass, baseClass)
// END_MESSAGE_MAP()
const AFX_MSGMAP* theClass::GetMessageMap() const { return GetThisMessageMap(); }
const AFX_MSGMAP* __stdcall theClass::GetThisMessageMap() {
static const AFX_MSGMAP_ENTRY _messageEntries[] = {// end of BEGIN_MESSAGE_MAP
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } // start of END_MESSAGE_MAP
};
static const AFX_MSGMAP messageMap =
{ &baseClass::GetThisMessageMap, &_messageEntries[0] }; return &messageMap;
}

ON_WM_XXXXX宏就是往_messageEntries[]里增加AFX_MSGMAP_ENTRY类型的对象。

虽然最近在做服务端,但是客户端这边我还是要参与下的,因为确实有个MFC的客户端存在。负责客户端的兄弟,事情也蛮多的,他想让我帮忙写个可以设置前景色和背景色的edit控件。

这显然是件容易的事情,总共也没几行代码,大致是这样的:

// EditEx.h
class CEditEx : public CEdit
{
public:
CEditEx(COLORREF clr_foreground, COLORREF clr_background);
~CEditEx(void);
private:
// text foreground color
COLORREF clr_foreground_;
// text background color
COLORREF clr_background_;
// background brush
CBrush brush_background_;
public:
DECLARE_MESSAGE_MAP()
afx_msg HBRUSH CtlColor(CDC* pDC, UINT /*nCtlColor*/);
public:
// set text color of the edit control
COLORREF SetTextColor(COLORREF color);
// set the background color of the edit control
COLORREF SetBackgroundColor(COLORREF color);
}; // EditEx.cpp
CEditEx::CEditEx(COLORREF clr_foreground, COLORREF clr_background)
: clr_foreground_(clr_foreground), clr_background_(clr_background)
, brush_background_(clr_background_)
{} CEditEx::~CEditEx(void)
{
brush_background_.DeleteObject();
} BEGIN_MESSAGE_MAP(CEditEx, CEdit)
ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP() HBRUSH CEditEx::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
// TODO: Change any attributes of the DC here
pDC->SetTextColor(clr_foreground_);
pDC->SetBkColor(clr_background_);
// TODO: Return a non-NULL brush if the parent's handler should not be called
return (HBRUSH)brush_background_.GetSafeHandle();
} // set text color
COLORREF CEditEx::SetTextColor(COLORREF color)
{
COLORREF old_color = clr_foreground_;
clr_foreground_ = color;
Invalidate(); return old_color;
} // set the background color of the edit control
COLORREF CEditEx::SetBackgroundColor(COLORREF color)
{
COLORREF old_color = clr_background_;
brush_background_.DeleteObject(); clr_background_ = color;
brush_background_.CreateSolidBrush(clr_background_);
Invalidate(); return old_color;
}

写完以后,也没啥感觉,因为这确实简单。不过后来我一想吧,其实这个方法是个通用的方法。对于common control,基本上都是可以用这个方法来设置前景和背景色的,既然如此那怎么把这个通用的东西抽象出来呢(当初一直在用VC6,每次遇到这种问题,都是这么解决的,也想过要整通用点,但是项目一结束,就懒了,算了吧,接踵而来的需求忙不停呢)?

首先还是想要把Message Map这个东西保留下来,毕竟这可是MFC的精华之一。第二要对所有common control都有效,这么想来模板是比较好的一种选择。既然如此,那么这个类看上去可能就是这样的:

// ControlEx.h
template <typename CBaseCtrl>
class CControlEx : public CBaseCtrl
{
public:
CControlEx(COLORREF clr_foreground, COLORREF clr_background);
~CControlEx(void);
private:
// text foreground color
COLORREF clr_foreground_;
// text background color
COLORREF clr_background_;
// background brush
CBrush brush_background_;
public:
DECLARE_MESSAGE_MAP()
afx_msg HBRUSH CtlColor(CDC* pDC, UINT /*nCtlColor*/);
public:
// set text color of the edit control
COLORREF SetTextColor(COLORREF color, BOOL invalidate = TRUE);
// set the background color of the edit control
COLORREF SetBackgroundColor(COLORREF color, BOOL invalidate = TRUE);
};

接下来的实现也比较简单:

template <typename CBaseCtrl>
CControlEx<CBaseCtrl>::CControlEx(COLORREF clr_foreground, COLORREF clr_background)
: clr_foreground_(clr_foreground), clr_background_(clr_background)
, brush_background_(clr_background_)
{} template <typename CBaseCtrl>
CControlEx<CBaseCtrl>::~CControlEx(void)
{
brush_background_.DeleteObject();
}

BEGIN_MESSAGE_MAP(CControlEx, CBaseCtrl)

    ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP() template <typename CBaseCtrl>
HBRUSH CControlEx<CBaseCtrl>::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
// TODO: Change any attributes of the DC here
pDC->SetTextColor(clr_foreground_);
pDC->SetBkColor(clr_background_);
// TODO: Return a non-NULL brush if the parent's handler should not be called
return (HBRUSH)brush_background_.GetSafeHandle();
} // set text color
template <typename CBaseCtrl>
COLORREF CControlEx<CBaseCtrl>::SetTextColor(COLORREF color)
{
COLORREF old_color = clr_foreground_;
clr_foreground_ = color;
Invalidate(); return old_color;
} // set the background color of the edit control
template <typename CBaseCtrl>
COLORREF CControlEx<CBaseCtrl>::SetBackgroundColor(COLORREF color)
{
COLORREF old_color = clr_background_;
brush_background_.DeleteObject(); clr_background_ = color;
brush_background_.CreateSolidBrush(clr_background_);
Invalidate(); return old_color;
}

但是标红的这里就不对了,因为缺少了模板函数定义的几个必要信息,比分说少了template <typename CBaseCtrl>等。要解决这个问题也不难,把BEGIN_MESSAGE_MAP自己改一改就可以了,问题不大。唯一的问题就是这个修改是不是永久有效(就目前来看,应该是没问题,貌似MFC也停止开发了(?))。另外就是看看MFC自己有没有提供,运气真的好,MFC自己提供了(VC6下没有),多好,都不用自己写了。它就是BEGIN_TEMPLATE_MESSAGE_MAP。

把标红的哪一行改成BEGIN_TEMPLATE_MESSAGE_MAP(CControlEx, CBaseCtrl, CBaseCtrl)就O了。

写完了,挺简单,我也是最近才发现,之前一直用VC6(从来就没在源代码里发现什么特别好用的东西,除了它在堆内存使用上的一点技巧外),挺悲剧的。

BEGIN_TEMPLATE_MESSAGE_MAP的更多相关文章

随机推荐

  1. Java 基础知识 问答

    1,Java为什么能跨平台运行?请简述原理. 因为Java程序编译之后的代码不是能被硬件系统直接运行的代码,而是一种“中间码”——字节码.然后不同的硬件平台上安装有不同的Java虚拟机(JVM),由J ...

  2. iOS-图文表并茂,手把手教你GCD

    前言 对初学者来说,GCD似乎是一道迈不过去的坎,很多人在同步.异步.串行.并行和死锁这几个名词的漩涡中渐渐放弃治疗.本文将使用图文表并茂的方式给大家形象地解释其中的原理和规律. 线程.任务和队列的概 ...

  3. SVN错误及处理

    SVN无法读取current修复方法 Can't read file : End of file found 文件:repository/db/txn_current.repository/db/cu ...

  4. FreeSWITCH中文语音包

    一.中文语音资源的获取 官方提供的资源:http://files.freeswitch.org/releases/sounds/ 自己录音 实在不行可以@我给你发一份. 二.中文资源的安装 英文资源的 ...

  5. 关于JS中apply方法的基本理解

    最近研究OpenLayers源码时,发现其中使用了比较多的apply方法,对其也是很不明白.于是上网经过多方面了解以及自己细细体会后,终于算是基本明白是其干什么的了,这里分享下.apply方法的造型是 ...

  6. 【OOAD】OOP的主要特征

    聚合 “虚包含” 不明确组合 “实包含” 明确 抽象(abstract)抽象:抽象是通过特定的实例抽取共同特征以后形成概念的过程.它强调主要特征,忽略次要特征.一个对象是现实世界中一个实体的抽象,一个 ...

  7. DuiLib 自定义识别控件

    遇到一个断点无法识别自定义的控件,运气比较好,一搜就搜出来了: 参考地址:http://www.bkjia.com/ASPjc/992050.html 主要是这个函数: CControlUI* CDi ...

  8. python 中的input

    渣渣之路. 一. 在python编程初学者指南中的第六章.使用参数和返回值的例子中: # -*- coding: utf-8 -*- def display(message): print messa ...

  9. Android Tips – 填坑手册

    出于: androidChina   http://www.androidchina.net/3595.html 学习 Android 至今,大大小小的坑没少踩,庆幸的是,在强大的搜索引擎与无私奉献的 ...

  10. [Selenium] 数字显示的月份转换为英文显示

    如果只需要英文的前三位字母,可以自己截取.