Using ON_UPDATE_COMMAND_UI with menu items and controls (2)


 If you have a dialog-based application, to which you have added a menu, any OnUpdate
handlers that you included in the dialog’s message map will never be called.  (Note that
the corresponding OnCommand handlers work fine).

By handling the dialog’s WM_KICKIDLE message, and mimicking MFC’s routing of its
UPDATE_UI messages, you can implement this with a little work.

The first step is to handle WM_KICKIDLE, which is #defined in afxpriv.h, by declaring
OnKickIdle(), and adding it to the message map.

//[in TESTDLG.H]
class CTestDlg : public CDialog
 . . .
 // Generated message map functions
 . . .
 afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);
 . . .
#include "stdafx.h"
#include "TestDlg.h"
#include <afxpriv.h>
. . . 
 . . .

The real work comes in defining OnKickIdle(). You need to
iterate over each item that might have an OnUpdate handler, set up a CCmdUI instance for
that item, and call CCmdUI::DoUpdate().  The OnKickIdle() I have written will update
the menu items in each of the first-level dropdown menus (e.g. the "File" menu,
the "Edit" menu, etc. from a normal app).  You will need to modify it if you
have further levels of submenus.  You will need a similar loop if you want to have
OnUpdate handlers for a status bar, toolbar, or specific dialog controls.

 CMenu* pMainMenu = GetMenu();
 CCmdUI cmdUI;
 for (UINT n = 0; n < pMainMenu->GetMenuItemCount(); ++n)
  CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
  cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
  for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)
   cmdUI.m_nIndex = i;
   cmdUI.m_nID = pSubMenu->GetMenuItemID(i);
   cmdUI.m_pMenu = pSubMenu;
   cmdUI.DoUpdate(this, FALSE);
 return TRUE;

Download demo project – 10 KB

More by Author

Must Read