CommandUI Message Handling with Popup Menus

Environment: Visual C++ 6.0 sp4, Windows 2000

Have you had problems with having a popup menu in a window and not being able to get its UpdateCommandUI messages ?

Simplest solution is (if it doesnt create any kind of impropriety) making the popup menu owned by CFrameWnd derived class. You may want to make a non CFrameWnd derived class own the menu though. This becomes a requirement when you have a dll, which you want to provide as a plug-in. You cannot have the mainframe class of the target application which links to the dll implement the message service routines for your popup menu! Even if it were ok, it would be pretty bad to have mainframe class have all popup menu service code as far as even modularity is concerned.

Add ON_WM_INITMENUPOPUP() to the message map,in the class which you assign as the owner in TrackPopUpMenu(); This handles windows messsage WM_INITMENUPOPUP send before a popup appears. TrackPopupMenu() would send this message before the menu is shown. Here is where we have to generate the UpdateCommandUI for the menu items.

void CPvMyWnd::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) 
{
 CFrameWnd* pwndFrame = (CFrameWnd* *)AfxGetMainWnd();
 if(NULL != pwndFrame)
  pwndFrame->SendMessage(WM_INITMENUPOPUP,WPARAM(pPopupMenu->m_hMenu),
                         MAKELPARAM(nIndex,bSysMenu));
}

This will let you have a pointer to a window of some type say CMyWnd own the menu and still have update command UI messages sent for each of the menu item ids. I would sincerely recommend you to take a look at the CFrameWnd :: OnInitPopUpMenu()function to get a full picture as to how it generates an Update Command UI message for popup menus.

Now one more issue you may face with a popup menu having a non CFrameWnd derived class as the parent - when you initiate a new UI like a dialog creation when the menu is still dropped down, it locks up the application because of the popup not being closed, so is the case with combo box drop downs. CFrameWnd takes care of these and this time you will have to do it yourself. The following line of code will help you there if you send a message to the owner window of the popup, before you want to create any other UI and it have the focus.

SendMessage(WM_CANCELMODE);

A typical situation is a client server application where u get a server message requiring a UI creation to convey some information to the user and this can happen when the user was having fun with his popup menu and the application appears to locked up till you minimize and restore causing popup state change. I think I wouldnt be pleased with such a treatment :), so the fix. Now combo box, he also shows some personality traits to pick up a fight whenever some new tries to cross roads while he has a dropdown. Well use the following function

void AFXAPI AfxCancelModes(HWND hWndRcvr) declared in afximpl.h

Look in winutil.cpp in mfc source. The handle to the window that may have a child combobox with a dropped down state represents hWndRcvr.

Going one step further How to send Update Command UI messages to any control in a given window..

 CCmdUI CmdUI;
 CmdUI.m_nID = IDC_MYBUTTON;
 CmdUI.m_pOther = CMyButtonWndClass;
 CmdUI.DoUpdate(this,FALSE);

This will send an UpdateCommandUI message to IDC_MYBUTTON to this class general scenario is that "this" is a pointer to a CDialog or CFormView .

Well how did I know? I read CFrameWnd :: OnInitPopUpMenu().

Adios



Comments

  • Can u help me?

    Posted by Amit Sebiz on 03/11/2004 12:54am

    Hi I am using a flexgrid ctrl in my applicacation. in which i i am showing a popup menu. But problem is that i have my code working fine in debug mode but in release mode, popup menu messages are not handled. I am using foollowing functions to track popup menu; void CSpiderView::OnMouseDownResults(short Button, short Shift, long x, long y) { intResultButton=Button; xResult=x; yResult=y; } void CSpiderView::OnClickResults() { CMenu menu; CMenu* ptrMenu; menu.LoadMenu(IDR_POPUP); ptrMenu=menu.GetSubMenu(0); if(m_resultsGrid.GetText()=="") { ptrMenu->EnableMenuItem(ID_POPUP_GOTOURL, MF_GRAYED); ptrMenu->EnableMenuItem(ID_POPUP_SENDEMAIL, MF_GRAYED); } else { ptrMenu->EnableMenuItem(ID_POPUP_GOTOURL, MF_ENABLED); ptrMenu->EnableMenuItem(ID_POPUP_SENDEMAIL, MF_ENABLED); } if(intResultButton==2) { ptrMenu->TrackPopupMenu ( TPM_LEFTALIGN|TPM_RIGHTBUTTON, xResult+32, yResult+175, this, NULL ); m_resultsGrid.SetCol(0); sMailId=m_resultsGrid.GetText(); m_resultsGrid.SetCol(1); sGoToUrl=m_resultsGrid.GetText(); } }

    Reply
  • A small mistake

    Posted by Legacy on 08/20/2002 12:00am

    Originally posted by: Santhosh Cheeran

    Hello,
    Here in the article I have shown the code

    CCmdUI CmdUI;
    CmdUI.m_nID = IDC_MYBUTTON;
    CmdUI.m_pOther = CMyButtonWndClass;
    CmdUI.DoUpdate(this,FALSE);

    The correct code is

    CmdUI.m_pOther = GetDlgItem(IDC_MYBUTTON);

    Sorry, just found out when I cut paste this to my project.
    Santhosh

    Reply
  • There's another way which the UpdateCommandUI can be handled

    Posted by Legacy on 01/31/2002 12:00am

    Originally posted by: Phil Thoren

    When doing the pPopupMenu->TrackPopupMenu, make the parent AfxGetMainWnd(). Although, I would assume any class which is part of the program and handles the WM_INITMENUPOPUP message could be a possible candidate for the menu's parent.
    I'm sure it would be possible to create a new class(if there is a problem with AfxGetMainWnd()) which handles the UPDATE_COMMAND_UI message map for each menu itemresouce ID needed. This class would obviously have to support the WM_INITMENUPOPUP message map, so CFrameWnd would be the first choice for a parent class.

    Reply
  • What about pop-up messages provided by ActiveX controls?

    Posted by Legacy on 09/30/2001 12:00am

    Originally posted by: Ghanashyam Lohar

    I have an ActiveX control with an embedded Rich Edit control. The rich edit's popup/context menu works well when the ActiveX is hosted from a Modeless dialog but the popup menu tracking(ie cmdui updations) and even the selection of menu item doext not work if i create the ActiveX control on a FormView of a aplitter pane. I have already a GetMessage Hook installed for handling keyboard messages for the ActiveX. Any help??

    Reply
  • Correct code

    Posted by Legacy on 07/02/2001 12:00am

    Originally posted by: Bob Hartzell

    The correct code for OnInitMenuPopup is given in The MFC Answer Book page 516 - 518. It is quit a bit more involved than stated here.

    Reply
  • Status bar messages for menu items

    Posted by Legacy on 05/08/2001 12:00am

    Originally posted by: Santhosh Cheeran

    CFrameWnd::GetMessageString

    Override this function to provide custom strings for command IDs. The default implementation simply loads the string specified by nID from the resource file. This function is called by the framework when the message string in the status bar needs updating. This is one another place a non CFrameWnd derived class being the parent creates problems, because the fn will be called in CFrameWnd class and it will have to be overloaded there to provide alternate strings in status bar corresponding to a menu item ID.

    Santhosh

    Reply
  • This doesn't work

    Posted by Legacy on 05/06/2001 12:00am

    Originally posted by: Adrian Sims

    Eventually this ends up calling the following code - the handlers for the CWnd derived class will never be called:
    
    (The handlers for the view, the frame and the app are called)

    BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
    AFX_CMDHANDLERINFO* pHandlerInfo)
    {
    CPushRoutingFrame push(this);

    // pump through current view FIRST
    CView* pView = GetActiveView();
    if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
    return TRUE;

    // then pump through frame
    if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
    return TRUE;

    // last but not least, pump through app
    CWinApp* pApp = AfxGetApp();
    if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
    return TRUE;

    return FALSE;
    }


    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds