MFC六大关键技术之仿真学习笔记(七)

来源:互联网 发布:linux内核编译命令 编辑:程序博客网 时间:2024/05/22 07:02

       从学习Windows的消息机制学习到MFC的消息映射,这是我最喜欢的一节。在Win32编程中,你回去定义各种消息,在WndProc中通过switch ..case..进行消息的分类处理。带着这种思维走进MFC,你会发现MFC采用一种消息映射表模式来简化消息处理。虽说书上理解起来很简单,关于消息如何在MFC框架中流动,其中原理是什么,这才是我们应该学会的,而不是仅仅学会如何使用。


*Message Mapping(消息映射)

当然我们希望消得以下流动


消息流动的终点在CCmdTarget,我们来看看消息如何实现以上的流动的,先来介绍两个数据结构:

typedef void (CCmdTarget::*AFX_PMSG)(void);struct AFX_MSGMAP_ENTRY{UINT nMessage;UINT nCode;UINT nID;UINT nLastID;UINT nSig;AFX_PMSG pfn;};
即:定义一个AFX_MSGMAP_ENTRY,通过结构我们可以获得消息对应的处理函数指针。

struct AFX_MSGMAP{AFX_MSGMAP* pBaseMessageMap;AFX_MSGMAP_ENTRY* lpEntries;};
即:通过AFX_MSGMAP,可以获得类成员的AFX_MSGMAP_ENTRY指针,从而获得类中所有消息映射,通过pBaseMessageMap获得基类的AFX_MSGMAP指针,这样可以实现"同宗"的流动。


同样,MFC也为了降低我们的工作量,构建了几个宏: DECLARE_MESSAGE_MAP,BEGIN_MESSAGE_MAP,END_MESSAGE_MAP。

来看看具体的定义:

#define DECLARE_MESSAGE_MAP() \static AFX_MSGMAP_ENTRY _messageEntries[]; \static AFX_MSGMAP messageMap; \virtual AFX_MSGMAP* GetMessageMap() const;
即:还是老套路,声明static变量来保证每个类中静态成员唯一,_messageEntries[]保存了类的消息映射信息,messageMap是子类和父类消息映射的纽带,消息通过向上流动可以实现遍历。虚函数GetMessageMap() 返回类对应的messageMap。

如图:


#define BEGIN_MESSAGE_MAP(theClass,baseClass) \AFX_MSGMAP* theClass::GetMessageMap() const \{ return &theClass::messageMap; } \AFX_MSGMAP theClass::messageMap = { &(baseClass::messageMap),(AFX_MSGMAP_ENTRY *)&(theClass::messageEntries) };\AFX_MSGMAP_ENTRY theClass::messageEntries[] = \    { #define END_MESSAGE_MAP() \{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0} \    };
即:BEGIN_MESSAGE_MAP与END_MESSAGE_MAP是成对出现的,看了宏定义确实如此,当然在实际代码中我们经常写到:

BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)ON_COMMAND(CMyWinAppid, 0)END_MESSAGE_MAP()
在俩宏的中间加入了我们的消息映射,当然ON_COMMAND宏我们也可以自行实现,只需要实现宏完成一个_messageEntries的初始化。

#define ON_COMMAND(id, memberFxn) \{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, \static_cast<AFX_PMSG> (memberFxn) },
当然,我们对END_MESSAGE_MAP()中的AfxSig_end定义为:

enum AfxSig{AfxSig_end = 0,     // [marks end of message map]}
代表消息映射的结束。


当然,这两个宏怎么用呢,其实很简单,下面用CView作为Demo:

头文件:

class CView :public CWnd{public:CView(){std::cout << "CView Constructor \n";}~CView(){std::cout << "CView Destructor \n";}DECLARE_MESSAGE_MAP()};
Cpp文件:

BEGIN_MESSAGE_MAP(CMyView, CView)ON_COMMAND(CMyViewid, 0)END_MESSAGE_MAP()

我们在main函数中测试一下:

void printlpEntries(AFX_MSGMAP_ENTRY *lpEntry){struct{int classid;char* classname;}classinfo[] ={CCmdTargetid, "CCmdTarget",CWinThreadid, "CWinThread",CWinAppid, "CWinApp",CMyWinAppid, "CMyWinApp",CWndid, "CWnd",CFrameWndid, "CFrameWnd",CMyFrameWndid, "CMyFrameWnd",CViewid, "CView",CMyViewid, "CMyView",CDocumentid, "CDocument",CMyDocid, "CMyDoc",0, "   "};for (int i = 0; classinfo[i].classid != 0; i++){if (classinfo[i].classid == lpEntry->nID){std::cout << lpEntry->nID << "  ";std::cout << classinfo[i].classname << std::endl;break;}}}void MsgMapPrinting(AFX_MSGMAP * pMessageMap){for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap){AFX_MSGMAP_ENTRY * lpEntry = pMessageMap->lpEntries;printlpEntries(lpEntry);}}int _tmain(int argc, _TCHAR* argv[]){CWinApp * pApp = AfxGetApp();pApp->InitApplication();pApp->InitInstance();pApp->Run();CMyDoc *pMyDoc = new CMyDoc;CMyView *pMyView = new CMyView;CFrameWnd * pMyFrame = (CFrameWnd *)pApp->m_pMainWnd;AFX_MSGMAP *pMessageMap = pMyDoc->GetMessageMap();std::cout << std::endl << "MyDoc MessageMap : " << std::endl;MsgMapPrinting(pMessageMap);pMessageMap = pMyView->GetMessageMap();std::cout << std::endl << "MyView MessageMap : " << std::endl;MsgMapPrinting(pMessageMap);pMessageMap = pMyFrame->GetMessageMap();std::cout << std::endl << "MyFrame MessageMap : " << std::endl;MsgMapPrinting(pMessageMap);pMessageMap = pApp->GetMessageMap();std::cout << std::endl << "pApp MessageMap : " << std::endl;MsgMapPrinting(pMessageMap);system("pause");return 0;}

结果:



0 0
原创粉丝点击