[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Make a menu

Posted on 2006-04-20
21
Medium Priority
?
381 Views
Last Modified: 2013-11-20
Hi,

On my main menu I have a drop down titled 'stuff', which has like 5 sub menu items:

    Stuff
      |- Apple
      |- Orange
      |- Pear

I'd like to have a sub menu for 'Orange', so when the user mouses over, a menu comes out of it with additional items. This is easy to do with the vc++ editor. But I need to read the number of items to put in there from disk, something like:

void CMainFrame::GetDropdownMenuItems(vector<CString> &vItems)
{
     // Populate vItems like 'itemA', 'itemB', 'itemC'
}

Then the menu should look like:

    Stuff
      |- Apple
      |- Orange ---- itemA
      |- Pear           itemB
                           itemC

I'm just not sure where to override what in order to get a chance to dynamically build the sub menu for 'Orange'?

Thanks
0
Comment
Question by:minnirok
  • 9
  • 7
  • 5
21 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 16501911
In the menu editor create a "stub" submenu with just one dummy item.

At runtime, call
    CMenu::GetMenuItemInfo()
for the "parent" of the cascading menu.  The value of
    MENUITEMINFO.hSubMenu
is an HMENU that you can attach to a new CMenu and you can now add and replace items at will.

I'll provide code and details if that is not enough.

-- Dan
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16501992
You could trap the WM_INITMENU message (in the MainFrame for example) and at that point modify the menu.  
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16502021
There is also a WM_INITMENUPOPUP - this should be fired when a popup menu is to be shown.  This might be more suitable to trap and modify the sub menu by adding the itemA, B and C that you want.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 7

Author Comment

by:minnirok
ID: 16502045
Hi,

@ Dan
Could you provide the code please?

@ Andy
When WM_INITMENU is called in mainframe, how will I know it is in fact this particular menu that is being popped up at that moment, compared to any of the other menus I have in mainframe?

Thanks
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16502321
<When WM_INITMENU is called in mainframe, how will I know it is in fact this particular menu that is being popped up at that moment, compared to any of the other menus I have in mainframe?>

I've not tested this but it should work (maybe there is a simpler way).  You get the ID of the first item.  If it is ID_MENU_APPLE then it is the menu you want to modify.
0
 
LVL 7

Author Comment

by:minnirok
ID: 16502383
Ahh hmm not sure if I did this right - I added a handler for WM_INITMENU to my child frame class (this menu item is for the child frame only) but no WM_INITMENU is ever getting sent, this never executes:

void CChildFrame::OnInitMenu(CMenu* pMenu)
{
    CMDIChildWnd::OnInitMenu(pMenu);

    AfxMessageBox("yes this handler was called");

    CString s;
    s.Format("the id is %i compared to %i", pMenu->GetMenuItemID(0),  ID_MENU_ITEM_APPLE);
    AfxMessageBox(s);
}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16502806
#define MID_OrangeSub1 2001
#define MID_OrangeSub2 2002
#define MID_OrangeSub3 2003

...
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
      //{{AFX_MSG_MAP(CMainFrame)
...
      ON_WM_INITMENUPOPUP()
      ON_UPDATE_COMMAND_UI_RANGE( MID_OrangeSub1, MID_OrangeSub3, OnUpdateOrangeSubs )   // added manually
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
      BOOL fRet;

      CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
      
      CString sMenuText;
      pPopupMenu->GetMenuString( 2, sMenuText, MF_BYPOSITION ); // eyeball check for debugging
      CMenu* pmnuOrange= pPopupMenu->GetSubMenu(2);
      if ( pmnuOrange == NULL ) {
            return;
      }
      pmnuOrange->GetMenuString( 0, sMenuText, MF_BYPOSITION );  // debugging eyeball verify

      pmnuOrange->RemoveMenu( 0, MF_BYPOSITION );  // remove the stub

      pmnuOrange->AppendMenu(MF_STRING, MID_OrangeSub1, "OrangeSub&1" );
      pmnuOrange->AppendMenu(MF_STRING, MID_OrangeSub2, "OrangeSub&2" );
      pmnuOrange->AppendMenu(MF_STRING, MID_OrangeSub2, "OrangeSub&3" );
}

void CMainFrame::OnUpdateOrangeSubs(CCmdUI* pCmdUI)
{
      pCmdUI->Enable(TRUE);
}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16502837
In the resource editor, I added a menu item labled "Orange" to an existing menu in an MDI app.   I set its properties to put a checkmark in the "Pop-Up" checkbox.
I then added an item to the resulting submenu and labeled it "item_stub" with an arbitrary command IS.

The rest  (all the stuff about OnUpdate and ON_UPDATE_COMMAND_UI_RANGE) is related to having the system enable the items so they won't be gray in the menu (unless there is a ON_COMMAND handler, they are gray and disabled)

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16502875
One other thing I just noticed... if the menus have already been added, you need to avoid adding them again :-) The simplest check might be to see if there are already three items.  For instance...

      if ( pmnuOrange->GetMenuItemCount() > 1 ) {
            ... do nothing...
      } else {
            ... delete item 0, and append the others...
      }
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16504940
Next day - an idea.
      CMenu* pMenu = GetMenu();
      CMenu* pSubMenu = pMenu->GetSubMenu(0);
      pSubMenu->InsertMenu(0, MF_BYPOSITION, 12345, _T("Hello"));

You can use code like the above to modify menus when you want to make a change.  For example in an SDI app you could use the code in the OnCreate of the main frame.  An MDI is slightly more complex (it has multiple menus depending on no view or one/many views).
Here you would change the menu once - rather than intercepting a message indicating a menu is to be shown and modifying/checking on multiple occasions.

This is probably better than modifying on the fly unless you have a dynamic menu (eg. undo showing the last 6 actions)
0
 
LVL 7

Author Comment

by:minnirok
ID: 16526417
Hi guys,

Ok so Dan I  tried your method, but I don't understand what this is doing:

     CString sMenuText;
     pPopupMenu->GetMenuString( 2, sMenuText, MF_BYPOSITION ); // eyeball check for debugging
     CMenu* pmnuOrange= pPopupMenu->GetSubMenu(2);
     if ( pmnuOrange == NULL ) {
          return;
     }

Why are you using '2' for GetMenuString()? Also, sMenuText always comes out emtpy after that call, pmnuOrange keeps coming out NULL too - ok so I'm doing something wrong, I just want to know what you're trying to do there.

Andy, everytime the user is going to mouse over this menu item, I have to scan a directory for XML files and display their names on the menu, so it has to be generated everytime they popup this menu. It is really unfortunate!

Thanks guys
0
 
LVL 7

Author Comment

by:minnirok
ID: 16526699
If I could just find the ID of the pPopupMenu I could compare it to the id of the menu resource I created in the editor, and if the index is the same I know they're about to popup the dynamic item.

I cannot find a way to get the resource ID of the passed pPopupMenu though, good gravy,

Thanks

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
    if (pPopupMenu.m_resID == MENU_ORANGE && nIndex == nIndexOfDynamicSubPopup) {

        // Now build the dynamic sub menu popup?
    }
}
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16526777
Question - do you want the menu creating once (when the app runs) or can it vary during the lifetime of the app?
If just once see my previous comment.
0
 
LVL 7

Author Comment

by:minnirok
ID: 16526995
Hi Andy,

Yeah it will vary during the lifetime - say they dump 3 XML's in my directory, when they popup the menu it should show those 3 XML filenames - if they add 10 more XML's to the dir and popup the menu again, it should show 10 filenames now,

I still can't find a way to figure which menu it is that's being worked with in OnInitMenuPopup, it is most cruel!

Thanks
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16527091
Next question.
Is it the main menu bar at the top we are talking about or a context menu (mouse right button click)?
0
 
LVL 7

Author Comment

by:minnirok
ID: 16527136
It's the main menu - more specifically, its a child frame menu, so when you open up one of my documents that menu becomes the main menu bar,

Thanks
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16527243
OK try this code
void CMainFrame::OnInitMenu(CMenu* pMenu)
{
      CMDIFrameWnd::OnInitMenu(pMenu);

      // TODO: Add your message handler code here
      CString s0, s1, s2;
      pMenu->GetMenuString(0, s0, MF_BYPOSITION);
      pMenu->GetMenuString(1, s1, MF_BYPOSITION);
      pMenu->GetMenuString(2, s2, MF_BYPOSITION);
      TRACE(_T("Menu Item 0-%s, 1-%s, 2-%s\n"), s0, s1, s2);
}


you should see it giving the 1-&File, 1-&Edit, 2-&View

So you see that pMenu is pointing to the menu bar and you can get the items on it.
0
 
LVL 45

Accepted Solution

by:
AndyAinscow earned 2000 total points
ID: 16527283
Now try this piece of code

void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
      CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

      // TODO: Add your message handler code here
      CString s0, s1, s2;
      pPopupMenu->GetMenuString(0, s0, MF_BYPOSITION);
      pPopupMenu->GetMenuString(1, s1, MF_BYPOSITION);
      pPopupMenu->GetMenuString(2, s2, MF_BYPOSITION);
      TRACE(_T("Menu Item (index %d) 0-%s, 1-%s, 2-%s\n"), nIndex, s0, s1, s2);
}

Now you should see it fire as you change the selection in the menu bar.
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16527299
You can use the previous two code snippets to check if it is your popup menu being opened (check text and index).

When the popup menu is being opened (pPopupMenu) then you can add/insert items to it on the fly
eg.
pPopupMenu->InsertMenu(0, MF_BYPOSITION, 12345, _T("Hello"));
0
 
LVL 7

Author Comment

by:minnirok
ID: 16527410
Hi Andy,

That's great, finally some progress! I'd like to open another question on this because I need some help actually creating that new menu, so if you can check the question listings in a minute, that would be great.

Thanks

0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16529093
>>Why are you using '2' for GetMenuString()?
The '2' is the position on the pre-built menu of the item that is a submenu.  The "eyeball check" is to help you ensure that you have found that menu during your debugging (for instance, it might be item #3).  If you were to find that it was item number 3 then your next step would be to modify the code I provided and in the places where I said 2, you would use 3 instead.
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question