更新处理函数在对话框的菜单中不能工作

 

void   CTestDlg::OnUpdateFileExit(CCmdUI*   pCmdUI 

{ 

        pCmdUI-> Enable(FALSE);   //没有显示为禁用. 

        pCmdUI-> SetCheck(TRUE);   //   没有文字前显示选定标记. 

        pCmdUI-> SetRadio(TRUE);   //   没有在文字前显示点. 

        pCmdUI-> SetText( "Close ");   //没有更改菜单文字. 

}   



 

原因 
在下拉菜单显示的时候,   WM_INITMENUPOPUP消息被先发送以显示菜单项。MFC   CFrameWnd::OnInitMenuPopup   函数遍历菜单项并为每个菜单项调用更新命令处理函数(如果有的话).菜单的外观被更新以反映它的状态(启用/禁用,选择/取消选择)   
更新用户界面机制在基于对话框的应用程序中不能工作,因为CDialog没有OnInitMenuPopup   处理函数,而使用CWnd 's   默认处理函数,该函数没有为菜单项调用更新命令处理函数。 

 


解决 
适用下列步骤解决此问题     

在消息映射中添加ON_WM_INITMENUPOPUP   项:   

 

BEGIN_MESSAGE_MAP(CTestDlg,   CDialog) 

  //{{AFX_MSG_MAP(CTestDlg) 

                                                ........................ 

                                                ........................ 

  //}}AFX_MSG_MAP 



  ON_WM_INITMENUPOPUP() 

END_MESSAGE_MAP()   



 

 

在你的对话框类中添加OnInitMenuPopup成员函数且复制下列代码到该函数(注意:代码基本上是从CFrameWnd::OnInitMenuPopup(在WinFrm.cpp中)复制过来的):   

void   CTestDlg::OnInitMenuPopup(CMenu   *pPopupMenu,   UINT   nIndex,BOOL   bSysMenu) 

{ 

        ASSERT(pPopupMenu   !=   NULL); 

        //   Check   the   enabled   state   of   various   menu   items. 



        CCmdUI   state; 

        state.m_pMenu   =   pPopupMenu; 

        ASSERT(state.m_pOther   ==   NULL); 

        ASSERT(state.m_pParentMenu   ==   NULL); 



        //   Determine   if   menu   is   popup   in   top-level   menu   and   set   m_pOther   to 

        //   it   if   so   (m_pParentMenu   ==   NULL   indicates   that   it   is   secondary   popup). 

        HMENU   hParentMenu; 

        if   (AfxGetThreadState()-> m_hTrackingMenu   ==   pPopupMenu-> m_hMenu) 

                state.m_pParentMenu   =   pPopupMenu;         //   Parent   ==   child   for   tracking   popup. 

        else   if   ((hParentMenu   =   ::GetMenu(m_hWnd))   !=   NULL) 

        { 

                CWnd*   pParent   =   this; 

                      //   Child   windows   don 't   have   menus--need   to   go   to   the   top! 

                if   (pParent   !=   NULL   && 

                      (hParentMenu   =   ::GetMenu(pParent-> m_hWnd))   !=   NULL) 

                { 

                      int   nIndexMax   =   ::GetMenuItemCount(hParentMenu); 

                      for   (int   nIndex   =   0;   nIndex   <   nIndexMax;   nIndex++) 

                      { 

                        if   (::GetSubMenu(hParentMenu,   nIndex)   ==   pPopupMenu-> m_hMenu) 

                        { 

                                //   When   popup   is   found,   m_pParentMenu   is   containing   menu. 

                                state.m_pParentMenu   =   CMenu::FromHandle(hParentMenu); 

                                break; 

                        } 

                      } 

                } 

        } 



        state.m_nIndexMax   =   pPopupMenu-> GetMenuItemCount(); 

        for   (state.m_nIndex   =   0;   state.m_nIndex   <   state.m_nIndexMax; 

            state.m_nIndex++) 

        { 

                state.m_nID   =   pPopupMenu-> GetMenuItemID(state.m_nIndex); 

                if   (state.m_nID   ==   0) 

                      continue;   //   Menu   separator   or   invalid   cmd   -   ignore   it. 



                ASSERT(state.m_pOther   ==   NULL); 

                ASSERT(state.m_pMenu   !=   NULL); 

                if   (state.m_nID   ==   (UINT)-1) 

                { 

                      //   Possibly   a   popup   menu,   route   to   first   item   of   that   popup. 

                      state.m_pSubMenu   =   pPopupMenu-> GetSubMenu(state.m_nIndex); 

                      if   (state.m_pSubMenu   ==   NULL   || 

                        (state.m_nID   =   state.m_pSubMenu-> GetMenuItemID(0))   ==   0   || 

                        state.m_nID   ==   (UINT)-1) 

                      { 

                        continue;               //   First   item   of   popup   can 't   be   routed   to. 

                      } 

                      state.DoUpdate(this,   TRUE);       //   Popups   are   never   auto   disabled.

                } 

                else 

                { 

                      //   Normal   menu   item. 

                      //   Auto   enable/disable   if   frame   window   has   m_bAutoMenuEnable 

                      //   set   and   command   is   _not_   a   system   command. 

                      state.m_pSubMenu   =   NULL; 

                      state.DoUpdate(this,   FALSE); 

                } 



                //   Adjust   for   menu   deletions   and   additions. 

                UINT   nCount   =   pPopupMenu-> GetMenuItemCount(); 

                if   (nCount   <   state.m_nIndexMax) 

                { 

                      state.m_nIndex   -=   (state.m_nIndexMax   -   nCount); 

                      while   (state.m_nIndex   <   nCount   && 

                        pPopupMenu-> GetMenuItemID(state.m_nIndex)   ==   state.m_nID) 

                      { 

                        state.m_nIndex++; 

                      } 

                } 

                state.m_nIndexMax   =   nCount; 

        } 

}   

状态 
设计使然。 

 

更多信息 
命令用户界面处理函数也被CWnd::OnCommand   调用以确认命令在传递之前没有被禁用。这就是禁用的菜单项的命令处理没有被调用的原因(虽然没有以灰色显示(不可用))。在这种情况下,菜单项没有被重画以反映菜单项的状态.这是Wincore.cpp   文件中的相关代码:   

//在传递命令之前,确定命令没有被禁用 

      CTestCmdUI   state; 

      state.m_nID   =   nID; 

      OnCmdMsg(nID,   CN_UPDATE_COMMAND_UI,   &state,   NULL); 

      if   (!state.m_bEnabled) 

      { 

            TRACE1( "Warning:   not   executing   disabled   command   %d\n ",   nID); 

            return   TRUE; 

      }   

重现此行为的步骤 
使用应用程序向导建立一个基于对话框的应用程序 

 


建立一个新的菜单资源,并且向其上添加文件和文件/退出菜单项。 


在对话框的属性中设置对话框的菜单为上述菜单. 


使用类向导为文件/退出菜单项添加一个UPDATE_COMMAND_UI处理并添加下列语句之一到处理函数。 


pCmdUI-> Enable(FALSE);   //没有显示为禁用. 
pCmdUI-> SetCheck(TRUE);   //   没有文字前显示选定标记. 
pCmdUI-> SetRadio(TRUE);   //   没有在文字前显示点. 
pCmdUI-> SetText( "Close ");   //没有更改菜单文字. 
编译运行此程序。

你可能感兴趣的:(对话框)