如何在富编辑控件中实现对 URL 的鼠标单击
Posted
技术标签:
【中文标题】如何在富编辑控件中实现对 URL 的鼠标单击【英文标题】:How to implement the mouse click for URLs at rich edit control 【发布时间】:2012-07-09 15:28:56 【问题描述】:我在对话框中添加了一个只读的 Rich Edit 2.0 控件(代码使用 C windows API,对话框是使用函数DialogBox 创建的)
在对话框回调中,在 WM_INITDIALOG 中,我添加了以下代码以启用 url 检测并启用事件 ENM_LINK 发送到父对话框而不是富编辑控件本身:
LRESULT mask = SendMessage(hWndText, EM_GETEVENTMASK, 0, 0); //hWndText is rich edit control
SendMessage(hWndText, EM_SETEVENTMASK, 0, mask | ENM_LINK);
::SendMessage(hWndText, EM_AUTOURLDETECT, TRUE, NULL);
在最初启动对话框时启用 url 检测有点麻烦(这似乎是一个已知问题或行为,因为富编辑控件只会启用修改文本的 url 检测)。但是,我通过在每个 WM_PAINT 事件上再次设置对话框文本来解决此问题。
代码通常可以正常工作。当鼠标悬停在 URL 上时,我还实现了以下代码以在浏览器中启动 URL:
case WM_NOTIFY:
plink = (ENLINK *) lParam;
switch(LOWORD(wParam))
case IDC_DISPLAY_TEXT_2: //this is ID for my rich edit control
szURL =m_strDisplay.Mid(plink->chrg.cpMin, plink->chrg.cpMax - plink->chrg.cpMin);
LaunchURL(szURL); //function to launch the url with default browser
break;
default:
break;
似乎每次我将鼠标悬停在 url 上时都会收到 WM_NOTIFY 事件。但是当我点击它时,我总是得到与鼠标悬停相同的事件。
基于ENLINK的结构,我应该在NMHDR结构中得到更详细的NM事件,但是值plink->nmhdr.code总是1803,甚至不是NM_HOVER(它的定义值是(NM_FIRST-13 ) 并且 NM_FIRST 是 (0U- 0U),所以在我的 64 位机器上 NM_HOVER 值是 4294967283)。我知道我在这里遗漏了一些东西。有人可以在这里点亮一些灯吗?如何获取富编辑控件的鼠标点击事件?
【问题讨论】:
另见Detect click on URL in RichEdit。 【参考方案1】:我认为您应该捕获EN_LINK 通知。我实现了以下代码。它使richedit 控件中的url 链接放置在父窗口中,而不是对话框中。您也可以根据对话对其进行调整。
考虑从代码开始:
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code) //NMHDR structure contains information about a notification message.
case EN_LINK:
ENLINK *enLinkInfo = (ENLINK *)lParam; // pointer to a ENLINK structure
然后,如果您选择在 LBUTTONUP 上启动 url,您必须检查 enLinkInfo->msg
中包含的值(不过,请记住为您的对话调整它)
if (enLinkInfo->msg == WM_LBUTTONUP)
// select all the text from enLinkInfo->chrg.cpMin to enLinkInfo->chrg.cpMax
// lauch the url
另外,你可以拦截WM_MOUSEMOVE:
if(enLinkInfo->msg == WM_MOUSEMOVE)
; // do nothing
希望对你有帮助。
【讨论】:
我可以看到附加值——检查enLinkInfo->msg
。好点子。【参考方案2】:
正如@A_nto2 的回答所示,拦截鼠标点击:
case WM_NOTIFY:
//NMHDR structure contains information about a notification message.
switch (((LPNMHDR)lParam)->code)
case EN_LINK:
ENLINK *enLinkInfo = (ENLINK *)lParam; // pointer to a ENLINK structure
if (enLinkInfo->msg == WM_LBUTTONUP)
但棘手的部分是获取被点击的链接。
在enLinkInfo->chrg
类型CHARRANGE
中单击的“范围”。
Detect click on URL in RichEdit 的答案建议使用 EM_EXSETSEL
和 enLinkInfo->chrg
。然后使用EM_GETSELTEXT
检索文本。
这适用于自动检测到的纯文本 URL (EM_AUTOURLDETECT
)。
问题在于友好名称超链接(即那些锚文本与 URL 本身不同的链接):
\rtf1\field\*\fldinst HYPERLINK "https://www.example.com"\fldrsltExample
(请注意,这些仅在 Rich Edit 4.1 和更高版本中受支持)
对于这些,CHARRANGE
指向HYPERLINK "https://www.example.com"
部分,该部分是隐藏的,无法使用EM_EXSETSEL
选择。实际上在 Windows 10 上可以选择。但在 Windows 7、Vista 和 XP 上无法选择。将EM_EXSETSEL
发送到这些系统会导致在隐藏部分之后选择一个零长度块。
因此,要么您必须返回富编辑缓冲区并扫描链接;或者使用其他方法来检索点击的文本。
在我的例子中,因为我只有在富编辑中的小文本,所以我使用了WM_GETTEXT
。它返回富编辑文档的纯文本版本,但以这种形式保留了友好名称超链接:
HYPERLINK "https://www.example.com" Example
CHARRANGE
指向 URL,奇怪的是包括前导引号:("https://www.example.com
)。
但索引对应于带有单字符 (LF) 行分隔符的文本。而 WM_GETTEXT
返回 CRLF 分隔符。因此,在使用CHARRANGE
提取 URL 之前,您必须将文本转换为 LF。
【讨论】:
感谢hyperlink
【参考方案3】:
根据EM_AUTOURLDETECT 的文档,您应该会收到EN_LINK 通知,这应该反映在nmhdr.code
中。据谷歌称,
#define EN_LINK 0x70B
即 7 * 256 + 11 = 1750 + 42 + 11 = 1803。
请注意,您的代码错过了对nmhdr.code == EN_LINK
的检查。
我不确定控件是否发送NM_HOVER
消息。
【讨论】:
谢谢,这解释了我所看到的。以上是关于如何在富编辑控件中实现对 URL 的鼠标单击的主要内容,如果未能解决你的问题,请参考以下文章
WS_EX_LAYERED 父级的 Win32 编辑控件在其背景透明时不接收鼠标/单击事件