设为首页 加入收藏

TOP

5.3.5 命令路由
2013-10-07 00:47:10 来源: 作者: 【 】 浏览:46
Tags:5.3.5 命令 路由

5.3.5  命令路由

视频精讲:光盘\video\05\命令路由.swf

MFC中的消息大致可分为3类,即命令消息(WM_COMMAND)、Windows消息(WM_***)及控件消息(WM_NOTIFY)。对于一般的Windows消息WM_***,所有派生于CWnd的类都可以接收,因此,MFC为处理这类消息所制定的路由方向是从派生类到基类的。而对命令消息WM_COMMAND而言,由于派生于CCmdTarget的类都有资格接收,MFC规定了处理这类消息时所采用的路由机制,如表5-3所示。

表5-3  处理WM_COMMAND消息时的路由次序

接收对象< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

处理次序

框架Frame

视图View

框架Frame本身

应用程序类CWinApp

视图View

视图View本身

文档Document

文档Document

文档Document本身

文档模板

下面将为大家详细地介绍MFC在处理命令消息时信息的流动过程。

(1)通过AfxWndProc()函数发送一个命令消息。

AfxWndProc()函数是一个全局函数,每执行一次就发送一个命令消息,函数的定义如下:

LRESULT AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
CWnd *pWnd)   //last param. pWnd is added by JJHou.
{
cout << "AfxWndProc()" << endl;
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
AfxWndProc()函数内部调用了AfxCallWndProc(),其定义如下:
LRESULT AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam)
{
cout << "AfxCallWndProc()" << endl;
LRESULT lResult = pWnd->WindowProc(nMsg, wParam, lParam);
return lResult;
}

(2)根据多态性,确定调用哪个对象的WindowProc()。

过程(1)中的WindowProc()函数是一个虚函数,对它的调用依赖于pWnd指针所指向的对象,WindowProc()的定义如下:

LRESULT CWnd::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
if (nMsg == WM_COMMAND)
{
if (OnCommand(wParam, lParam))
return 1L;
else
return (LRESULT)DefWindowProc(nMsg, wParam, lParam);
}
pMessageMap = GetMessageMap();
for (;pMessageMap != NULL;pMessageMap = pMessageMap->pBaseMessageMap)
{
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
return 0;
}
即如果是命令消息WM_COMMAND,CWnd::WindowProc()将根据当前this指针所指对象来决定需要调用哪个类的(如CFrameWnd类或CView类等)OnCommand()函数。假设this指针指向框架类,则其最终会调用CWnd对象的OnCommand(),而该函数又呼叫了另一个虚函数OnWndMsg(),此时,同样要由this指针的指向决定具体的调用对象。由于前面假设了this指针是指向框架类的,所以,这里将调用框架类的OncmdMsg(),其定义如下:
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode)
{
cout << "CFrameWnd::OnCmdMsg()" << endl;
CView* pView = GetActiveView();
if (pView->OnCmdMsg(nID, nCode))
return TRUE;
if (CWnd::OnCmdMsg(nID, nCode))
return TRUE;
CWinApp* pApp = AfxGetApp();
if (pApp->OnCmdMsg(nID, nCode))
return TRUE;
return FALSE;
}

(3)开始消息路由。

从过程2的pView→OnCmdMsg()可知,最先调用的是CView类的OnCmdMsg(),其定义如下:

BOOL CView::OnCmdMsg(UINT nID, int nCode)
{
cout << "CView::OnCmdMsg()" << endl;
if (CWnd::OnCmdMsg(nID, nCode))  
return TRUE;
BOOL bHandled = FALSE;
bHandled = m_pDocument->OnCmdMsg(nID, nCode);
return bHandled;
}
此时将体现出视图View在处理命令消息时的次序,即先视图本身后文档对象,因此,这里首先调用CWnd类的OnCmdMsg()函数。由于CWnd类并没有重载该函数,所以实际上调用的是CWnd的基类CCmdTarget的OnCmdMsg(),其定义如下:
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode)
{
cout << "CCmdTarget::OnCmdMsg()" << endl;
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMessageMap)
{
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
return FALSE;
}
如果在消息映射表中查找到相应的消息项,就调用其对应的消息响应函数,结束命令路由;否则,根据视图View处理命令消息的次序,退回到CView::OnCmdMsg()处,并调用CDocument::OnCmdMsg(),其定义如下:
BOOL CDocument::OnCmdMsg(UINT nID, int nCode)
{
cout << "CDocument::OnCmdMsg()" << endl;
if (CCmdTarget::OnCmdMsg(nID, nCode))
return TRUE;
return FALSE;
}

如果在映射表中没有找到相应的消息项,则退回到pView→OnCmdMsg()处,并按照框架Frame处理命令消息的次序,继续执行CWnd::OnCmdMsg()。如前所述,由于CWnd类没重载OnCmdMsg(),所以实际上调用的是CCmdTarget::OnCmdMsg()。如果在映射表中还是没找到相应的消息项,就返回至CFrameWnd::OnCmdMsg()处,转而呼叫CWinApp::OnCmdMsg()(亦即调用CCmdTarget::OnCmdMsg())。如果仍然找不到对应的信息,则命令消息也无处可去了,只能将false返回到WindowProc()中,调用DefWindowProc()结束命令路由。
【责任编辑:云霞 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇5.4.1 基本思路 下一篇5.3.4 消息映射

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: