CWnd的派生类-4、 对话框的命令路由

如果给对话框附加了一个菜单资源,进入ClassWizard向导,就能够发现,不仅该对话框能够映射该菜单命令,而且主框架窗口、视图、文档、应用类也可以。如果一个对话框(无论弹出和重叠,不分模态与非模态)的父窗口是主框架或视图,该对话框的菜单命令就可以在多个对象中处理,它的处理路由是:对话框→视图→文档对象→主框架→应用类。一旦命令消息被处理,将不再继续传递。由此可知,对话框的命令处理路由与主框架的命令处理路由非常接近,只是增加了一个最高的优先处理对象:对话框本身。不难推测,在对话框的命令消息处理函数CDialog::OnCmdMsg()中,首先搜寻对象本身的消息映射,如果没有找到相应的处理函数,则将控制权交给主框架窗口(如果是它的父窗口)。下面就一起来阅读这段代码,证实这一推断。

BOOL CDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,

         AFX_CMDHANDLERINFO* pHandlerInfo)

{        //首先搜寻该对象的消息映射

         if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

                  return TRUE;

//该对象没有处理这个命令消息

/*如果该命令ID在[0x8000,0xF000)范围内,则向下传递,否则终止处理。

命令范围[8000 ,FFFF]:全局命令,包括菜单、加速键、系统命令等

命令范围[F000 , FFFF]:Windows系统命令(不被传递)*/

if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||

                          !IS_COMMAND_ID(nID) || nID >= 0xf000)

         {

                  return FALSE;       // not routed any further

         }

         //如果是全局的菜单、加速键等命令,则将处理权转交给父窗口

         CWnd* pOwner = GetParent();

         if (pOwner != NULL)

         {

                  ASSERT(pOwner != this);

         //由父窗口负责命令路由

                  if (pOwner->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

                          return TRUE;

         }

         /*如果父窗口也没有处理该命令,则将处理权交给应用类。在父窗口不是主框架窗口时,以下代码是有意义的*/

         CWinThread* pThread = AfxGetThread();

         if (pThread != NULL)

         {                if (pThread->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

                          return TRUE;

         }

         return FALSE;

}

从以上代码可知,只有菜单、加速键等全局命令,才可能被对话框传送给父窗口。至于我们最关心的对话框按钮命令,则不被传递。如果父窗口不是主框架,应用类得到最后的处理机会;如果父窗口是主框架,最后关于应用类(UI线程)的代码是多余的。那么如果在对话框创建时,指定了视图作为父窗口会怎样呢?读者应该注意到,视图是主框架的子窗口,而对话框是弹出或重叠窗口,所以对话框不能被视图控制,而最终由主框架接管。

posted on 2011-05-09 18:09  carekee  阅读(381)  评论(0编辑  收藏  举报