
Introduction
This code provides a simple way to remove disabled items from a context menu.
It is not good coding practice to remove disabled menu items from an application's main menus but it is often desirable to do
this for popup context menus.
Using the code
Using the code is very simple. Add the two files "ReducedMenu.h" and
"ReducedMenu.cpp" to your project.
Cast the menu you wish to popup to a CReducedMenu so that our custom TrackPopupMenu function is called
((CReducedMenu*) menu.GetSubMenu(0))->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y ,AfxGetMainWnd());
Points of Interest
The CReducedMenu class uses the internal class
CEnabledCmdUI derived from CCmdUI to check the enabled state
for each menu item using the MFC command update handlers. You can find the same
class definition in MFC's WinCore.cpp.
class CReducedMenu: public CMenu
{
public:
CReducedMenu() {}
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd,
LPCRECT lpRect = NULL );
protected:
void CullDisabledItems(CMenu* pMenu);
class CEnabledCmdUI : public CCmdUI
{
public:
CEnabledCmdUI():m_bEnabled(false) {}
virtual void Enable(BOOL bOn)
{
m_bEnabled = bOn;
m_bEnableChanged = TRUE;
}
virtual void SetCheck(int nCheck) {}
virtual void SetRadio(BOOL bOn) {}
virtual void SetText(LPCTSTR) {}
BOOL m_bEnabled;
}
};
The actual removal of disabled items is called recursively
for any sub menus. After the disabled items are removed, surplus
separators are then removed.
BOOL CReducedMenu::TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect )
{
CullDisabledItems(this);
return CMenu::TrackPopupMenu( nFlags,x,y,pWnd,lpRect);
}
void CReducedMenu::CullDisabledItems(CMenu* pMenu)
{
CEnabledCmdUI state;
UINT n;
for(n =0; n < pMenu->GetMenuItemCount(); n++)
{
state.m_nID = pMenu->GetMenuItemID( n );
if (state.m_nID == 0)
continue;
if (state.m_nID == (UINT)-1)
{
CMenu* pSub=pMenu->GetSubMenu(n);
if(pSub)
CullDisabledItems(pSub);
}
else
{
AfxGetMainWnd()->OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL);
if( !state.m_bEnabled )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
}
}
for (n =0; n < pMenu->GetMenuItemCount(); n++)
{
UINT nID = pMenu->GetMenuItemID( n );
if (nID == 0 && (n == 0 || n == pMenu->GetMenuItemCount()-1) )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
if (n > 0 && nID == 0 && pMenu->GetMenuItemID( n-1 ) == 0 )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
}
}