65.9K
CodeProject 正在变化。 阅读更多。
Home

CRichEditCtrl 和弹出菜单

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.83/5 (27投票s)

2002 年 2 月 16 日

3分钟阅读

viewsIcon

226669

downloadIcon

2876

为 CRichEditCtrl 提供弹出菜单。

引言

欢迎各位读者。本文的目的是演示如何从 CRicheditCtrl 中显示弹出菜单,当用户单击鼠标右键后,但首先讲一点历史

诚然...一开始是 Windows 3.1 的魔力,而且还不错(相对而言)。 随着时间的流逝,看似没有发生什么意外,但私底下微软(tm)的大批奴才们正疯狂地工作,以便按时发布新的魔法...Windows 95。

作为扩展备受推崇的 CEdit 类的公共控件的一部分,引入了 CRicheditCtrl CEdit 类有一些很棒的魔法,当您右键单击它时,会弹出一个小上下文菜单,这样您就可以剪切、粘贴等等。 程序员看到了这一点,认为它还不错(相对而言)。 但遗憾的是,CRicheditCtrl 没有直接显示上下文菜单的方法...所以这不好,实际上是一个非常痛苦的事情!

因此,各位读者,我认为现在是时候提供一篇快速文章,介绍如何在单击鼠标右键后从 CRicheditCtrl 显示上下文菜单了。

然而,亲爱的读者,似乎遇到了一些问题,由于他们自己最清楚的原因,微软决定不让它变得完全容易(即简单的覆盖)来捕获来自 CRichEditCtrl WM_RBUTTONDOWN 事件。 他们选择让它更复杂一点(而且我确信有一个非常好的理由,我只是没有研究。)

首先,创建一个简单的基于对话框的应用程序,我们将其命名为 PopupDemo。 添加一个菜单资源(我们将其命名为 IDR_MENU1),另外,在主对话框中添加一个 CRichEditCtrl 成员, m_RichEdit,其 ID 为 IDC_RICHEDIT。 别忘了添加

AfxInitRichEdit();

在应用程序的 Initinstance 中,否则应用程序将无法工作...

接下来,使用类向导为 PopupDemoDlg 生成一个 OnInitDialog 成员函数。 在其中放入以下内容

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

这告诉 RichEditCtrl 我们希望将所有鼠标事件反映到主窗口。 我们这样做是为了可以在 WM_NOTIFY 处理程序中捕获它们。

要捕获这些被反映到 CPopupDemoDlg 的鼠标事件,我们需要在 OnNotify 上捕获该事件才能做到这一点...

RichEditCtrl 将消息 "EN_MSGFILTER" 发送到父级,现在要获取已反映的哪个消息(因为它可能是左键单击或鼠标移动),我们需要检查消息过滤器,因此我们将 lParam 强制转换为 MSGFILTER *

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

而不是通常的;

//
NMHDR * pnmh = (LPNMHDR)lParam;
//

然后我们检查结果并测试哪个实际的 Windows 消息以及哪个窗口我们正在处理。

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

所以最终的 OnNotify 处理程序看起来像...
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);
}

然而...亲爱的读者 - 有一种更隐蔽、更快速的方法来编写一种处理相同事件的方法。 只需覆盖 PreTranslateMessage(MSG* pMsg)(再次使用类向导)。 执行类似于以下操作(这不在下载文件中)

//
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);
}
//

是的 - 尽管可能还有其他方法可以做到这一点,但亲爱的读者,这些是我发现的实现目标的最简单的两种方法。 看哪,它是好的。

这就是本课的结尾。

© . All rights reserved.