6.5. Menus

6.5.1. How do I get a pointer to the menu bar in a MDI app?

QUESTION:

I'm writing a MDI application and I have problems to get a pointer to the actual menu bar. The normal construction doesn't seem to work in MDI:

CMenu *menu;
menu = GetMenu()->GetSubMenu(0);

How can I get a pointer to the menu bar to update the menu?ANSWER:

AfxGetApp()->m_pMainWnd->GetMenu()->GetSubMenu(n);

mlinar@pollux.usc.edu, Mitch Mlinar, 6/8/95

6.5.2. How do I implement a right-mouse popup-menu?

///////////////////////////////////////////////////////////////////
// WM_RBUTTONDOWN handler.
//
// Trap this message and display the button properties popup menu.
// The main frame receives the popup menu messages. This allows the
// status bar to be updated with the help text.
// ///////////////////////////////////////////////////////////////////
void CAppButton::OnRButtonDown(UINT flags, CPoint point)
{
    CMenu menu;
    CMenu *submenu;
    // load the menu
    menu.LoadMenu(IDR_LAUNCH);
    // get the popup menu
    submenu = menu.GetSubMenu(0);
    // convert to screen coordinates
    ClientToScreen(&point);
    // post the menu
    submenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
                            point.x, point.y,
                            AfxGetApp()->m_pMainWnd,NULL);
}

johnm@unipalm.co.uk, programmer.win32, 7/12/95

It's better to use RBUTTONUP instead, however right-clicking on dialog controls doesn't generate RBUTTONUP and RBUTTONDOWN messages.

If it's necessary to treat this situation too, a program have to catch WM_PARENTNOTIFY message in Win3.x and WinNT and WM_CONTEXTMENU in Windows 95. Here's a code:

// May be dialog too:
BEGIN_MESSAGE_MAP(CMyPropertyPage, CPropertyPage)
    //{{AFX_MSG_MAP(CMyPropertyPage)
    ON_WM_RBUTTONUP()
    ON_WM_PARENTNOTIFY()
    ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
void CMyPropertyPage::OnRButtonUp(UINT nFlags, CPoint point)=20
{
    PopupMenu (&point);
}

void CMyPropertyPage::OnParentNotify(UINT message, LPARAM lParam)
{
    if (message !=3D WM_RBUTTONDOWN)
        CPropertyPage::OnParentNotify(message, lParam);
    else
    {
        CPoint pt(LOWORD(lParam),HIWORD(lParam));
        PopupMenu (&pt);
    }
}

LONG CMyPropertyPage::OnContextMenu (UINT wParam, LONG lParam)
{
    CPoint pt(LOWORD(lParam),HIWORD(lParam));
    ScreenToClient (&pt);
    PopupMenu (&pt);
    return 0;
}

//*****************************************************************

void CMyPropertyPage::PopupMenu(CPoint* pt)
{
    ASSERT(m_idContextMenu !=3D 0);
    ASSERT(nSubMenu >=3D 0);
    ClientToScreen (pt);
    CMenu FloatingMenu;
    VERIFY(FloatingMenu.LoadMenu(ID_POPUP_MENU));
    CMenu* pPopupMenu =3D FloatingMenu.GetSubMenu (0);
    ASSERT(pPopupMenu !=3D NULL);
    pPopupMenu->TrackPopupMenu (TPM_LEFTALIGN | TPM_RIGHTBUTTON,=20
                                pt->x, pt->y, this);
}

PaulACost@msn.com - via email, 10/15/95

6.5.3. How do I dynamically change the mainframe menu?

CMenu newMenu;
newMenu.LoadMenu (IDR_MENU1);
AfxGetMainWnd()->SetMenu( &newMenu );
AfxGetMainWnd()->DrawMenuBar();
newMenu.Detach ();

Arun Rao, MSMFC, 6/27/95

6.5.4. How do I 'attach' a menu to a window's creation/destruction?

{Note the original question talked about dialogs, but you can interpolate this code to any kind of window that you want to have change the menu.}

One of the ways to do this is as follows……

Declare a variable CMenu pNewMenu in one of the dialog class.
Handle the WM_INITDIALOG and WM_CLOSE messages in the dialog class as follows.
 
BOOL CMydlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // Load the IDR_MYFRAME menu
    pNewMenu = new CMenu;
    pNewMenu->LoadMenu(IDR_MYFRAME);
    // Set the mainframe menu to mainframe.
    ((CMainFrame *)AfxGetMainWnd())->SetMenu(pNewMenu);
    return TRUE;
}

And

void CMydlg::OnClose()
{
    // Detach the previous HMenu handle from the object.
    pNewMenu->Detach();
    pNewMenu->LoadMenu(IDR_MAINFRAME);
    // Restore the mainframe menu.
    ((CMainFrame *)AfxGetMainWnd())->SetMenu(pNewMenu);
    CDialog::OnClose();
}

If there are other methods of closing the dialog (example- By clicking a button in the Dialog), then The code given above in OnClose handler, must be put in the button click handler.

Sanjeev Kumar, MSMFC, 6/23/95