Reduced Context Menus






3.78/5 (5 votes)
Nov 6, 2002
1 min read

81476

2297
This code provides a simple way to remove disabled items from a context menu.
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 to test if a command is enabled or not. Taken from MFC's WinCore.cpp
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;
// go through each menu item and remove disabled items
for(n =0; n < pMenu->GetMenuItemCount(); n++)
{
state.m_nID = pMenu->GetMenuItemID( n );
// menu separator or invalid cmd - ignore it
if (state.m_nID == 0)
continue;
if (state.m_nID == (UINT)-1)
{
// possibly a popup menu, route to child menu if so
CMenu* pSub=pMenu->GetSubMenu(n);
if(pSub)
CullDisabledItems(pSub);
}
else
{
// normal menu item, Remove it if the command is disabled
AfxGetMainWnd()->OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL);
if( !state.m_bEnabled )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
}
}
// now remove spare separators
for (n =0; n < pMenu->GetMenuItemCount(); n++)
{
UINT nID = pMenu->GetMenuItemID( n );
// if separator is first or last item in menu- remove it
if (nID == 0 && (n == 0 || n == pMenu->GetMenuItemCount()-1) )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
// if two adjacent separators, remove one
if (n > 0 && nID == 0 && pMenu->GetMenuItemID( n-1 ) == 0 )
{
pMenu->DeleteMenu( n--, MF_BYPOSITION );
}
}
}
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.