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

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要让这个消息处理函数处理对话框的消息,需要在函数内部添加对话框消息的处理代码,常见的对话框消息有: - WM_INITDIALOG:对话框初始化消息,在对话框显示时被发送,可以在该消息进行对话框控件的初始化操作。 - WM_COMMAND:控件命令消息,当用户激活对话框的控件(如按钮、菜单等)时被发送,可以在该消息根据控件ID执行相应的操作。 - WM_CLOSE:关闭对话框消息,在用户关闭对话框时被发送,可以在该消息进行清理资源等操作。 下面是一个简单的示例代码,演示如何处理对话框初始化消息和确定按钮的点击消息: ``` INT_PTR CALLBACK MyDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: // 初始化对话框控件 SetWindowText(hwndDlg, "My Dialog"); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: // 处理确定按钮的逻辑 EndDialog(hwndDlg, IDOK); return TRUE; case IDCANCEL: // 处理取消按钮的逻辑 EndDialog(hwndDlg, IDCANCEL); return TRUE; } break; case WM_CLOSE: // 处理对话框关闭的逻辑 EndDialog(hwndDlg, IDCANCEL); return TRUE; } return FALSE; } ``` 在该示例代码,当收到WM_INITDIALOG消息时,我们使用SetWindowText函数设置对话框标题;当收到WM_COMMAND消息时,根据控件ID判断用户点击的是确定按钮还是取消按钮,并调用EndDialog函数关闭对话框;当收到WM_CLOSE消息时,直接调用EndDialog函数关闭对话框

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值