2
votes

I have a menu that contains submenus.

eg:

  • Item1
  • Item2
  • Item3
    • item A
    • Item B

Item3 has items under it.

At any given time 1, 2, or the items under 3 should be checked. Since I don't have an ID for Item3 I have to use the MF_BYPOSITION indicator when I try to set a check on Item3 to indicate one of its children has a checkmark. Item3 should have a checkmark if A or B are checked. I am able to check items 1 and 2 and A and B - but can't figure out item3.

I have not been able to successfully use either ::CheckMenuItem() or ModifyMenu() to set the check mark.

Can someone point me to an example that does this successfully? The docs seem to indicate it can be done, but I have been unable to do it.

EDIT

This is for a menu that is set as the menu for a dlg box. The menu bar has three items - one of which drops down to what is shown above.

Note also, it is used as a popup for a right click, but I will take any suggestions to work in either case.

2
Is this a popup menu or part of the menu bar?flashk

2 Answers

2
votes

I've done this before for popup menus. You will need to access the submenu by position, instead of ID. Using your example above, Item 3 would be at position 2:

CMenu popupMenu;
popupMenu.LoadMenu(IDR_MYMENU);
popupMenu.GetSubMenu(0)->CheckMenuItem(2,MF_BYPOSITION|MF_CHECKED);
.
.
.
popupMenu.GetSubMenu(0)->TrackPopupMenu(...);

However, I haven't done this with items in the menu bar.

EDIT by Tim the OP:

For completeness

To get it to work with the menu item you have to get the hmenu

// MENU_POSITION is the zero based location of the menu you want to use. (file, edit, view, help... etc)
HMENU mainMenu = ::GetMenu(m_hWnd);
HMENU subMenu = GetSubMenu( mainMenu, MENU_POSITION);
SetMenuState(subMenu);
1
votes

A few moments ago I had a similar problem - a standard MFC menu bar containing at least one submenu, and the need to be able to add a check mark to the submenu parent item, when any of the submenu child items were checked.

The easiest solution (for me) turned out to be as simple as performing the update in the standard OnUpdateMenuItem(CCmdUI* pCmdUI) call. In my case I used ON_UPDATE_COMMAND_UI_RANGE() to feed a bunch of menu IDs into the same update call, but the principal is the same for a single ON_UPDATE_COMMAND_UI() map.

The code I used (edited to be more easily inserted into other people's work) is:

void CMyApp::OnUpdateMenu(CCmdUI* pCmdUI)
{
   // Note, a submenu parent (which has no editable ID in the resource editor) has the SAME ID as the first child item
   if (pCmdUI->m_nID == ID_FIRST_CHILD_MENU && pCmdUI->m_pSubMenu != NULL) {
      // Get the child menu so we can see if any child items are checked
      CMenu* pSubMenu = pCmdUI->m_pSubMenu;
      BOOL fChildChecked = FALSE;
      for (UINT i = 0; !fChildChecked && i < pSubMenu->GetMenuItemCount(); ++i) {
         // Do something to decide if this child item should be checked...
         UINT nChildID = pSubMenu->GetMenuItemID(i);
         fChildChecked = IsThisChildChecked(nChildID);
      }

      // The POSITION of the current menu item is stored in pCmdUI->m_nIndex
      CMenu* pMenu = pCmdUI->m_pMenu;
      UINT flags = MF_BYPOSITION;
      if (fActiveChild) flags |= MF_CHECKED;
      pMenu->CheckMenuItem(pCmdUI->m_nIndex, flags);
   }

   // Set the enabled state of the menu item as you see fit...
   pCmdUI->Enable(TRUE);
}

Et voilà the submenu item automagically gains a check mark when any of its child menu items has a check mark.

Hope this helps others looking for similar solutions!

John