如何在富编辑控件中实现对 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_EXSETSELenLinkInfo->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 编辑控件在其背景透明时不接收鼠标/单击事件

如何在 MFC 中的对话框上阻止鼠标输入

如何使用 WebBrowser 控件模拟鼠标单击

如何在wps表格中插入日历表

当鼠标悬停在 DIV 上时,如何使某些控件可见并与 DIV 重叠? [关闭]

如何处理 WPF 中的鼠标滚轮单击事件?