Link to home
Start Free TrialLog in
Avatar of cbursk
cbursk

asked on

How to disable a submenu item that is a popup menu?

Scenario - Programming in Visual C++ version 5 using MFC wherever possible.  I have a top level pulldown menu, several of teh submenu items are themselves popup menus which leads to submenu items and even further popup menus.

I need to be able to disable or enable or even remove andleter reinsert,  one or several of these popups during runtime depending in my applications internal state.  Enabling/disableing a submenu item that is not a popup is easy, each submenu item has an ID so I just have class wizard overide the ON_UPDATE_COMMAND_UI handlers and enable or disable it there.

But the popup portions of the submenu items do not have an ID associtated with them that I can see in the resource editor or class wizard.  How do I traverse/ find the popup submenu item to perform the enable/disabling/removing/inserting?  And once I find it how do I perform the enable/disabling/removing/inserting?  Any help would be appreciated.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nietod
nietod

You can remove a menu item by using RemoveMenu() function.  Again you will need to use MF_BYPOSITION when deleteing a sub-menu item.

You can insert a menu item into a menu by using InsertMenuItem() function

Let me know if you have any questions.
Note you might find you need to maintain a data structure of some sort that helps you track the position of the menus and their other attributes.  You might creating a structure like

struct MenuItem
{
   bool  Cmd; // Command?  or sub-menu?
   bool Ena;  // Enabled?
   UINT ID; // Command ID, if a command.
   HMENU MenHnd; // Sub-menu handle, if a submenu.
   vector<MenuItem> *SubMenDat; // -> data fro sub-menu.
};

then creating arrays of these (using vectors) to track information for each menu, like

vector<MenuItem> MenuData;
Avatar of cbursk

ASKER

Part of the probelm that I'm still having is reaching into the submenus.

Using EnableMenuItem by postion doen't work if I use a number exceeding the top level menu pull downs ( I have six toplevel pulldowns ) and even if I use MF_BYCOMMAND and pass n the submeu item ID it still doesn't work.  Of  course using the ON_UPDATE_COMMAND_UI handlers works fine foe enabling and disabling submenu items that I can setup thru class wizard, but I have somemany that it may become problematic.

I have tried reaching into the submenus to get to the popups using:

MainFrame::OnInitMenu

HMENU subMenu = GetSubMenu(      m_hMenuDefault, // handle of menu
   0 // menu item position
  );

BOOL flag = EnableMenuItem(  
 subMenu, // handle to menu
5, // menu item to enable, disable, or gray  
MF_BYPOSITION | MF_GRAYED // menu item flags
 );

but this doen't seem to work either.

My requirements are what is forcing me to actually remove a submenu item popup in some cases and I had planned on using the RemoveMenu() function to do that if I could just get there.

Thanks for your help.  ANy further ideas?
Avatar of cbursk

ASKER

What is real strange is that I have just discovered that using the above method for getting the , RemoveMenu seems to work fine, but EnableMenuItem doesn't?!?
Did you check that the handles you are getting are valid?  make sure none are NULL?

Are there 6 items in the sub-menu you obtained?  You specified an index of 5, that is for the 6th item.
Try using the MF_DISABLED flag instead.  If I remember correctly there is something a little weird about dissabled sub-menu items--that;s why you usually don't see them.  I don't remember the details, I ended up writting my own menus instead of using the built-in ones..
Avatar of cbursk

ASKER

OK - I'm officially a pain... but I'm getting closer to a solution.

Here is my latest weird behavior...
In MainFrame::OnInitMenu

CMenu* submenu = pMenu->GetSubMenu( 2 );

if ( NULL != subMenu )
{  
   int itemCount = submenu->GetMenuItemCount();

   // stiple out all menu items
    for ( int i = 0; i < itemCount; i++ )
   {
      submenu->EnableMenuItem( i,
                                                MF_BYPOSITION |                                                                                                                                                                                                                                                                                                                                       MF_GRAYED          );
   }
}

The EnableMenuItem is now working for me except... it is only disabling the popups.  Using MF_DISABLED has the same results.  That would be fine except I have a mixture of popups and non-popups.  I am checking my handles before using them and I am within the index range.
>>  I'm officially a pain
Apparently you haven't seen other questions.

I didn't realize this was for MFC.  of course now I see it in the original quesiton....

After you dissable an item, use the GetMenuState() or GetMenuItemInfo() function to see if the item is really being dissabled.
Avatar of cbursk

ASKER

OK folks here what I got going, don't understand why ther is a difference but I'm tired of fight the system...

In MainFrame::OnInitMenu
----------------------------------------------------------
// The following for some reason will only stiple the
// popups in the submenu
CMenu* submenu1 = pMenu->GetSubMenu( 0 );

int z1 = submenu1->GetMenuItemCount();

for ( int i1 = 0; i1 < z1; i1++ )
{
      // disabling only popups???????????
      submenu1->EnableMenuItem( i1, MF_BYPOSITION | MF_GRAYED );

}

However in MainFrame::OnInitMenuPopup
---------------------------------------------------------
int z = pPopupMenu->GetMenuItemCount();

for ( int i = 0; i < z; i++ )
{
      pPopupMenu->EnableMenuItem( i, MF_BYPOSITION | MF_GRAYED );

}

Does stiple everything.  Although for me it seems to work only if I don't touch any of the menu items in MainFrame::OnInitMenu??  Don't know why...

Furter more if I replace the above code in OnInitMenuPopup with:
int z = pPopupMenu->GetMenuItemCount();

   for ( int i = 0; i < z; i++ )
   {
      LPMENUITEMINFO lpmii = new MENUITEMINFO;

      memset( lpmii, 0, sizeof(MENUITEMINFO) );

      lpmii->cbSize = sizeof(MENUITEMINFO);
      lpmii->fMask = MIIM_CHECKMARKS |  MIIM_DATA       | MIIM_ID  | MIIM_STATE  |MIIM_SUBMENU    | MIIM_TYPE;
 

      HMENU hMenu = pPopupMenu->GetSafeHmenu( );

     BOOL flag1 = GetMenuItemInfo( hMenu,
                                   i,
                                   TRUE,  
                                   lpmii  
                                  );

     // hSubMenu = Handle to the drop-down menu or           //  submenu associated with
     // the menu item. If the menu item is not an item           // that opens a drop-down
     // menu or submenu, this member is NULL.                  //------------------------------------------------------
     if ( NULL == lpmii->hSubMenu )
     {
        pPopupMenu->EnableMenuItem( i, MF_BYPOSITION | MF_GRAYED );
     }

   }

By changing the last if to look for NULL or !NULL I can exclude popup or vica-versa
What may be happening is that when you make changes in the OnInitMenu() function, the MFC system then undoes some of those changes (probably trying to help you) before it calls OnInitMenuPopup().  
You should be able to confirm that.  Check to see if the change is successfully made when you are in OnInitMenu() (which is what i was getting at before) and then check to see if the change was undone when OnIniutMenuPopup() is called.