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

 

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 ");   //没有更改菜单文字. 
编译运行此程序。

转载于:https://www.cnblogs.com/rogee/archive/2011/01/03/1924389.html

你可能感兴趣的:(更新处理函数在对话框的菜单中不能工作)