zoukankan      html  css  js  c++  java
  • BEGIN_TEMPLATE_MESSAGE_MAP

    最近转做服务端开发,或多或少有点坑爹的感觉。目前正在恶补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,每次遇到这种问题,都是这么解决的,也想过要整通用点,但是项目一结束,就懒了,算了吧Sad smile,接踵而来的需求忙不停呢)?

    首先还是想要把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(从来就没在源代码里发现什么特别好用的东西,除了它在堆内存使用上的一点技巧外),挺悲剧的。

  • 相关阅读:
    curl continue
    actor
    nginx
    jmx additional port
    diff
    lsof
    zk reconnect
    Python:Python基础(一)
    Python:初识Python(二)
    Python:初识Python(一)
  • 原文地址:https://www.cnblogs.com/wpcockroach/p/3259662.html
Copyright © 2011-2022 走看看