CRichEditCtrl 和弹出菜单






3.83/5 (27投票s)
2002 年 2 月 16 日
3分钟阅读

226669

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); } //
是的 - 尽管可能还有其他方法可以做到这一点,但亲爱的读者,这些是我发现的实现目标的最简单的两种方法。 看哪,它是好的。
这就是本课的结尾。