4

我在对话框中添加了一个只读的 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)。我知道我在这里遗漏了一些东西。有人可以在这里点亮一些灯吗?如何获取富编辑控件的鼠标单击事件?

4

3 回答 3

7

I think you should capture the EN_LINK notification. I implemented the following code. It enables a url link in a richedit control placed into the parent window, not into a dialog. You could adapt it for your dialog, as well.

Consider beginning with the code:

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

then, if you choose to launch url on LBUTTONUP, you have to check the value contained in enLinkInfo->msg (remember to adapt it for your dialog, though)

 if (enLinkInfo->msg == WM_LBUTTONUP) {
// select all the text from enLinkInfo->chrg.cpMin to enLinkInfo->chrg.cpMax
// lauch the url

}

Besides, you can intercept WM_MOUSEMOVE:

if(enLinkInfo->msg == WM_MOUSEMOVE) {
                ; // do nothing
}

Hope it helps.

于 2012-07-09T16:12:54.977 回答
4

正如@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一个人得到一个在 type中被点击的“范围” CHARRANGE

在 RichEdit 中检测点击 URL的答案建议EM_EXSETSEL使用enLinkInfo->chrg. 然后使用EM_GETSELTEXT检索文本。

这适用于自动检测到的纯文本 URL ( EM_AUTOURLDETECT)。

一个问题是友好名称超链接(即那些锚文本与 URL 本身不同的链接):

{\rtf1{\field{\*\fldinst{ HYPERLINK "https://www.example.com"}}{\fldrslt{Example}}}}

(请注意,这些仅在 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

指向 URL的CHARRANGE点,奇怪地包括前导引号:( "https://www.example.com)。

但索引对应于带有单字符 (LF) 行分隔符的文本。而WM_GETTEXT返回 CRLF 分隔符。因此,您必须先将文本转换为 LF,然后再使用CHARRANGE.

于 2016-01-16T08:37:17.373 回答
2

根据EM_AUTOURLDETECT的文档,您应该收到一个EN_LINK通知,该通知应该反映在nmhdr.code. 据谷歌称,

#define EN_LINK 0x70B

即 7 * 256 + 11 = 1750 + 42 + 11 = 1803。

请注意,您的代码缺少对nmhdr.code == EN_LINK.

我不确定控件是否发送NM_HOVER消息。

于 2012-07-09T15:37:56.020 回答