Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CRichEditCtrl and a popup menu

0.00/5 (No votes)
15 Feb 2002 1  
Providing a popup menu for the CRichEditCtrl

Introduction

Welcome Gentle reader. The purpose of this article is to demonstrate the method with which to display a popup menu from a CRicheditCtrl after the user has right clicked the mouse, but first a little history

Yea verily...in the beginning there was the magic of Windows 3.1 and lo it was good(ish). And so it came to pass that years went by seemingly without incident but lo behind the scenes hoards of Microsoft(tm) minions worked feverishly for an on time release of new magic...Windows 95.

As part of the common controls to extend the much revered CEdit class, CRicheditCtrl was introduced. And CEdit class had some good magic for when you right clicked on it, a wee context menu popped up so one could cut, paste and so on. Programmers looked on this and saw it was good (ish). But alas CRicheditCtrl had no direct method for displaying a context menu...and so it is not good, it is in fact a darn pain!

So gentle reader I thought it was about time to provide a quick article on how to display a context menu from a CRicheditCtrl after a right click of the mouse.

Alas though there seemed to be a hitch dear reader as, for reasons best known to themselves, MS decided it wasn't going to make it totally easy (i.e. a simple override) to catch the WM_RBUTTONDOWN event from a CRichEditCtrl. They chose instead to make it a a bit more complicated (and I'm sure there's a very good reason which I just haven't researched.)

To begin with create a simple dialog based application, we'll call ours PopupDemo. Add a menu resource ( let's call ours IDR_MENU1) also, in the main dialog add a CRichEditCtrl member, m_RichEdit with IDC_RICHEDIT. Don't Forget to add

AfxInitRichEdit();

in the application's Initinstance or the application will not work...

Next, use the class wizard to generate an OnInitDialog member function for PopupDemoDlg. Inside this put the following

BOOL CPopupDemoDlg::OnInitDialog() 
{ 
   m_RichEdit.SetEventMask(ENM_MOUSEEVENTS);
...

This tells the RichEditCtrl that we want all mouse events reflected to the main window. We do this so we can catch them in a WM_NOTIFY handler.

To catch these mouse events which are being reflected to CPopupDemoDlg, we need to trap the event on OnNotify to do this...

The RichEditCtrl sends the message "EN_MSGFILTER" to the parent, now to get at which message has been reflected (because it could be a left click or a mouse move) we need to examine the message filter, so we cast lParam to MSGFILTER *

//

MSGFILTER * lpMsgFilter = (MSGFILTER *)lParam;
//

instead of the usual;

//

NMHDR * pnmh = (LPNMHDR)lParam;
//

Then we examine the result and test for which actual windows message and which window we're dealing with.

if ((wParam == IDC_RICHEDIT) && (lpMsgFilter->nmhdr.code == EN_MSGFILTER)
    & (lpMsgFilter->msg == WM_RBUTTONDOWN))

So the final OnNotify handler looks something like...

BOOL CPopupDemoDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
MSGFILTER * lpMsgFilter = (MSGFILTER *)lParam; 
if ((wParam == IDC_RICHEDIT) && (lpMsgFilter->nmhdr.code == EN_MSGFILTER)   
    && (lpMsgFilter->msg == WM_RBUTTONDOWN))                                       
  
    {//if we get through here, we have trapped the right click event of the richeditctrl! 

     CPoint point;                                            
     ::GetCursorPos(&point); //where is the mouse?

     CMenu menu; //lets display out context menu :) 

     DWORD dwSelectionMade;                                       
     VERIFY(menu.LoadMenu(IDR_MENU1) );  
     CMenu *pmenuPopup = menu.GetSubMenu(0);
     ASSERT(pmenuPopup != NULL);                                       
     dwSelectionMade = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|TPM_LEFTBUTTON|
                                                       TPM_NONOTIFY|TPM_RETURNCMD),
                                                       point.x, point.y, this
                                );                                
  
     pmenuPopup->DestroyMenu(); 
     // Exercise for the reader...deal with the user's choice here :)                                      

     }
 return CDialog::OnNotify(wParam, lParam, pResult);
}

However... dear reader - there is a sneaker, faster way to code a method for dealing with the same event. Just override PreTranslateMessage(MSG* pMsg) (again use the class wizard). Do something similar to the following (this is not in the download files)

//

BOOL CPopupDemoDlg::PreTranslateMessage(MSG* pMsg)
{ 
    if (pMsg->message ==WM_RBUTTONDOWN)
    {
        CWnd * pWnd = (CWnd*) GetDlgItem(IDC_RICHEDIT); 
        if (pWnd ==GetFocus())
        {
              CMenu menu;
              DWORD dwSelectionMade; VERIFY(menu.LoadMenu(IDR_MENU1));
              CMenu *pmenuPopup = menu.GetSubMenu(0);
              ASSERT(pmenuPopup != NULL);                                    
              dwSelectionMade = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|
                                                                TPM_LEFTBUTTON|
                                                                TPM_NONOTIFY|
                                                                TPM_RETURNCMD),
                                                                 pMsg->pt.x, 
                                                                 pMsg->pt.y, this
                                                          );  
              pmenuPopup->DestroyMenu();
             //excercise for the reader...deal with the selection the user has made here

             return TRUE;
               }
    }
    return CDialog::PreTranslateMessage(pMsg);
}
//

Yea - though there are probably other ways of doing this these, gentle reader, are what I have found to be two of the easiest ways of achieving the aim. And lo, it is good.

Here-in ends the lesson.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here