最近在看深入浅出MFC,获益匪浅,不过这里有个疑问:在命令消息的传递中,书中说(P430)窗口得到这个消息,首先给View,View检查自己的Message Map,如果没有这个消息对应的处理函数,则转递给Document,同样,Document检查自己的Message Map,没有的话再转递,以此类推。可是反观代码:BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE; // then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
} return FALSE;
}在CView::OnCmdMsg 中,View没有检查自己的Message Map的操作呀,而是直接转递给了CWnd::OnCmdMsg。对于CDocument::OnCmdMsg也有同样的问题。而且似乎无论通过那条传递路径,最终都是由CCmdTarget::OnCmdMsg进行最后的处理,中间所经过的所有类中,都没有检查自己的Message Map。不知是怎么回事,望各位不吝赐教。
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE; // then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
} return FALSE;
}在CView::OnCmdMsg 中,View没有检查自己的Message Map的操作呀,而是直接转递给了CWnd::OnCmdMsg。对于CDocument::OnCmdMsg也有同样的问题。而且似乎无论通过那条传递路径,最终都是由CCmdTarget::OnCmdMsg进行最后的处理,中间所经过的所有类中,都没有检查自己的Message Map。不知是怎么回事,望各位不吝赐教。
解决方案 »
- 关于数据实时保存、调用的几个问题
- 如何解决资源无法释放的问题,急!!
- 在调用EndModal之后PostMessage后消息处理顺序问题
- about checkbox问题
- 背景重画问题,谢谢。
- CRichEditCtrl 类怎么添加背景图片,给个详细的例子
- 请教一个bitblt的问题????高手请进
- 谁能用自己的话解释一下SetViewportExt函数??
- 用atl 编写桌面应用程序 和 用wtl 编写桌面应用程序有什么区别??
- 请问如何能得到当前所有窗口及子窗口的句柄?最好能给一个vc的例子,谢谢!
- 创建一线程用于进行基于UDP的网络数据接收,为什么总是无法接受数据呢!
- 类似超级兔子的软件 外包价格
return TRUE;
就是说OnCmdMsg处理了,就返回TRUE了。
如果没处理就继续:
m_pDocument->OnCmdMsg
AFX_CMDHANDLERINFO* pHandlerInfo)
{
....// look through message map to see if it applies to usfor (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
{if (lpEntry != NULL)
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}
return FALSE; // not handled
}GetMessageMap()是一个虚函数,this指针指向CView中的OnCmdMsg(),上面的for循环实现了从类CView到类CCmdTarget的消息映射的遍历。就是说,命令消息传递中,中间所经过的所有类中,其实都在检查自己的Message Map。是不是这样?
for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。
CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。
to:visualwind“CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。”----------------------------------------------------------------------我是说“有可能”会被检查多次,就是说最坏的情况下。那个for循环不就决定了,在最坏情况下,只有在回溯到CCmdTarget,检查完CCmdTarget的Message Map后,仍没有找到消息对应的处理函数,就会被赋值为NULL,然后循环终止吗?还是没有这个可能?BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
....// look through message map to see if it applies to usfor (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
{ if (lpEntry != NULL)
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}
return FALSE; // not handled
}
LZ这里没明白这个for循环里面在干什么。
虽然调用的是CCmdTarget::OnCmdMsg,但是你的窗口对象是继承于CCmdTarget的,for (pMessageMap = GetMessageMap()的时候这个GetMessageMap是你的继承类的GetMessageMap,而不是CCmdTarget的GetMessageMap。那么代码:
for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
{ if (lpEntry != NULL)
return _AfxDispatchCmdMsg(this, nID, nCode,
lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
}
}for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
是在遍历消息这个继承类的消息响应map,这里遍历的是继承类的map对象,也就是BEGIN_MESSAGE_MAP那堆宏。lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
这里查找消息nMsg对应的响应函数,赋值给pMessageMap->lpEntries
然后return _AfxDispatchCmdMsg就是执行消息响应函数。如果循环没有找到对应的消息响应函数的话,就继续m_pDocument->OnCmdMsg,在Document里面找,如果还没找到的话再进一步回溯。
其实应该不会去查CCmdTarget的Message Map,因为这个没有意义。
pMessageMap = pMessageMap->pBaseMap)上面的for循环中,pMessageMap = pMessageMap->pBaseMap不就是使pMessageMap指向其父类的消息映射表吗?这样下一次循环中,lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);不就是在其父类的消息映射表中查找吗?以此类推,只有在CCmdTarget类中,pBaseMap才指向NULL,就是说,遍历CCmdTarget的消息映射表后,循环结束啊~~PS:我是新手,所以有好多问题可能很浅显,见笑~~
LZ参考一下文章:
http://tech.ddvip.com/2006-04/11444435404354.html
讲得很清楚
pMessageMap = pMessageMap->pBaseMap)这个for循环有可能进行下一次循环,那么在下次循环前,执行语句pMessageMap = pMessageMap->pBaseMap,再查看pMessageMap 是否 == NULL,进而决定是否进行下一次循环。关键问题是:执行语句pMessageMap = pMessageMap->pBaseMap后,pMessageMap指向哪里?
我分析着觉得是指向它父类的Message Map 结构,进而调用AfxFindMessageEntry(pMessageMap->lpEntries, nMsg,nCode, nID); 查找他父类的MessageEntry[](由lpEntries所指)中有无对应的消息处理函数。