学习mfc时知道了mfc的消息处理机制是有着顺序的,首先是视图类CView类先处理,如果视图类不处理消息则会由文档类CDocument处理,如果文档类不处理消息则会由框架类CFrameWnd处理,加入框架类不处理则会由应用程序类CWinApp类处理,但是这个顺序是怎么来的呢,跟踪MFC代码调试发现是跟MFC库代码顺序有关,相关MFC函数代码如下
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID,
nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID,
nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(
nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
由代码可以看出来MFC的消息处理会在此处进行选择对象处理,而首先选择的就是视图类,如图所示
在视图类的消息处理函数中,如果会处理会进入文档类处理,如图所示
因此我们给视图类,文档类,框架类都加入消息循环,然后加入ON_COMMAND处理新建消息
运行程序,结果如下
视图类处理了这个ON_COMMAND消息,屏蔽视图类和文档类的这个消息,结果如下
此时则是框架类处理了这个消息,那么我们如何修改这个处理顺序呢,只需要重写框架类的OnCmdMsg方法即可
首先新建一个自己要优先处理消息的类,这个类继承自CCmdTarget并加入消息循环宏
class CMyTarget : public CCmdTarget
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyTarget,CCmdTarget)
ON_COMMAND(ID_NEW,OnNew)
END_MESSAGE_MAP()
然后在这个类中加入消息处理函数
void CMyTarget::OnNew()
{
AfxMessageBox("自己的类处理新建被点击");
}
定义框架类
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_COMMAND(ID_NEW,OnNew)
ON_WM_CREATE()
END_MESSAGE_MAP(
并重写OnCmdMsg方法,代码如下
BOOL CMyFrameWnd::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo )
{
CMyTarget cMyTarget;
if (cMyTarget.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return CFrameWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}
在这个重写方法里定义CMyTarget对象,然后调用cMyTarget.OnCmdMsg方法处理消息,最后为了安全,再次调用MFC的消息处理函数CFrameWnd::OnCmdMsg函数,此时结果应当会弹出“自己的类处理新建被点击”对话框,结果运行结果如下
至此成功修改了MFC消息处理顺序,因此我们可以看出MFC的消息处理顺序可以根据自己的需要任意修改而不是一成不变的