MFC的消息映射机制

MFC的消息映射机制其实还是挺简单的, 下面用一个小的程序来演一下其工作原理.

/*----------------------------------------------------------------------------
                            MFC 消息映射机制的演示程序
    作者:Ning 2014/02/28
    备注:
    审核:

----------------------------------------------------------------------------*/
typedef int MessageID;
#define afx_msg

/*===========================================================================

    功能:  定义消息映射结构体  2014/02/28

===========================================================================*/
class CmdTarget;
typedef void (CmdTarget::*MemberFunc)();

// 定义一个消息结构, 关联消息ID与消息响应函数
struct MsgMap
{
    MessageID m_Msg;
    MemberFunc m_pFunc;
};

typedef MsgMap* MsgMapPtr;

struct MessageChain
{
    const MessageChain* m_pParent;
    MsgMapPtr m_MessageEntries;
};

/*===========================================================================

    功能: 消息映射基类  2014/02/28

===========================================================================*/
class CmdTarget
{
public:
    void MessageHandler(MessageID A_Msg);

protected:
    virtual const MessageChain* GetMsgChain() = 0;

private:
    static const MessageChain m_MsgChain;
};//end CmdTarget
const MessageChain CmdTarget::m_MsgChain = {NULL, NULL};

/*----------------------------------------------------------------------------
    2014/02/28 功能:  在消息映射数组中搜索与ID对应的消息处理函数并执行
----------------------------------------------------------------------------*/
void CmdTarget::MessageHandler(MessageID A_Msg)
{
    // 从当前窗口中获取消息映射数组, 查找是否有对应的消息处理函数
    const MessageChain* pMsgChain = GetMsgChain();
    while(pMsgChain != NULL)
    {
        MsgMapPtr pEntries = pMsgChain->m_MessageEntries;
        if(pEntries != NULL)
        {
            for(int i = 0; ; i++)
            {
                if(pEntries[i].m_Msg == 0)
                    break;

                if(pEntries[i].m_Msg == A_Msg)
                {
                    // 调用消息处理函数(这句稍稍有点复杂)
                    (this->*pEntries[i].m_pFunc)(); 
                    return;
                }
            }
        }
        // 子类没有消息函数, 再从父类中查找
        pMsgChain = pMsgChain->m_pParent;
    }
}

/*----------------------------------------------------------------------------
    2014/02/28 功能:  类中声明消息映射相关的变量与函数
----------------------------------------------------------------------------*/
#define MY_DECLARE_MESSAGE_MAP()    \
    private:\
        static MsgMap m_MsgMap[];\
        static const MessageChain m_MsgChain;\
    protected:\
        virtual const MessageChain* GetMsgChain();

/*----------------------------------------------------------------------------
    2014/02/28 功能:  开始建立消息映射数组
----------------------------------------------------------------------------*/
#define  MY_BEGIN_MESSAGE_MAP(derived_class, base_class)    \
    const MessageChain MyWindow::m_MsgChain = {&CmdTarget::m_MsgChain, \
    &MyWindow::m_MsgMap[0]};    \
    const MessageChain* MyWindow::GetMsgChain() \
    {return &MyWindow::m_MsgChain;} \
    MsgMap MyWindow::m_MsgMap[] = { 

/*----------------------------------------------------------------------------
    2014/02/28 功能:  结束消息映射数组
    从C++指针中不能获取数组的尺寸,所以把最近一个元素定义成0,就可以明确定位数组结束的位置.
----------------------------------------------------------------------------*/
#define  MY_END_MESSAGE_MAP()   \
        {0, NULL}   \
    };

/*----------------------------------------------------------------------------
    2014/02/28 功能:  添加数组元素的宏
----------------------------------------------------------------------------*/
#define MY_ON_CONTROL(id, func)     {id, (MemberFunc)&func},

/*===========================================================================

    功能:  模拟一个用户定义的窗口  2014/02/28

===========================================================================*/
#define ID_PAINT        0x00000001
#define ID_BUTTON       0xFFFF0001

class MyWindow : public CmdTarget
{
protected:
    //{{AFX_MSG(Derived)
    afx_msg void OnButtonDown();
    afx_msg void OnPaint();
    //}}AFX_MSG
    MY_DECLARE_MESSAGE_MAP() // 声明消息映射相关的成员
};

MY_BEGIN_MESSAGE_MAP(MyWindow, CmdTarget)
//{{AFX_MY_BEGIN_MESSAGE_MAP
    MY_ON_CONTROL(ID_BUTTON, OnButtonDown)  // 成员函数与控件绑定
    MY_ON_CONTROL(ID_PAINT, OnPaint)        // 成员函数与窗口消息绑定
//}}AFX
MY_END_MESSAGE_MAP()

void MyWindow::OnButtonDown()
{
    printf("ButtonDown\n");
}

void MyWindow::OnPaint()
{
    printf("Paint\n");
}

/*===========================================================================

    功能:  主函数  2014/02/28

===========================================================================*/
int main(int argc, char* argv[])
{
    MyWindow oDerived;
    // 模拟由系统消息泵向窗口发送消息
    oDerived.MessageHandler(ID_BUTTON);
    oDerived.MessageHandler(ID_PAINT);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值