我的 RichEdit 控件可以包含可点击的链接吗?
我想向编辑控件或 Rich Edit 2.0 控件显示一系列字符串.之后,我希望显示的一些文本带有下划线和蓝色.然后可以单击这些带下划线的文本以打开另一个对话框或某种对话框.
I want to display a series of strings to an Edit Control or Rich Edit 2.0 Control. After that, I want some of the text displayed to be underlined and in blue. These underlined texts can then be clicked to open another dialog or some sort.
有没有办法做到这一点?
Is there a way to do this?
推荐答案
Rich Edit 2.0 仅支持 自动 RichEdit 超链接 而 Rich Edit 4.1 和更高版本 (msftedit.dll) 支持 友好名称超链接.
Rich Edit 2.0 only supports Automatic RichEdit Hyperlinks while Rich Edit 4.1 and newer (msftedit.dll) supports Friendly Name Hyperlinks.
您可以通过使用 CFE_LINK
和 CFE_HIDDEN
字符格式标志.使用 CFE_LINK
标记文本并通过应用 CFE_HIDDEN
隐藏 URL.处理 EN_LINK代码> 通知以对点击做出反应.此时,您必须进行一些解析以从富文本中提取隐藏的 URL.
You can emulate friendly name hyperlinks in Rich Edit 2.0 by using a combination of the CFE_LINK
and CFE_HIDDEN
character formatting flags. Mark the text with CFE_LINK
and hide the URL by applying CFE_HIDDEN
. Handle the EN_LINK
notification to react on clicks. At this point you would have to do some parsing to extract the hidden URL from the rich text.
或者只使用 CFE_LINK
作为文本并使用 std::map
将文本映射到 URL.只要存在文本到 URL 的 1:1 映射,这将起作用.
Alternatively just use CFE_LINK
for the text and use a std::map
to map text to URLs. This will work as long as there is a 1:1 mapping of text to URL.
我刚刚注意到您只是想在单击链接时打开另一个对话框",因此在您的情况下应用 CFE_LINK
就足够了.
I just noted that you just want "to open another dialog" when a link is clicked, so just applying CFE_LINK
should be good enough in your case.
编辑 2: 如果您不需要显示格式化文本并且也不需要滚动,我建议使用 SysLink 控件.SysLink 控件显示的链接比 RichEdit 控件中的链接具有更好的可访问性.前者支持 TAB 键来浏览各个链接,而后者不支持.
Edit 2: If you don't need to display formatted text and you also don't need scrolling, I suggest to use the SysLink control. Links displayed by the SysLink control have better accessibility than links in the RichEdit control. The former supports the TAB key to navigate through the individual links whereas the latter does not.
免责声明:以下代码已在 Win 10 下测试,并带有创作者更新.我还没有时间在旧操作系统版本下测试它.
Disclaimer: The following code has been tested under Win 10 with creators update. I haven't found time yet to test it under older OS versions.
- 如果您的 Visual Studio 版本支持,请在
CWinApp
派生类的InitInstance()
方法中调用AfxInitRichEdit5()
.否则调用LoadLibraryW(L"msftedit.dll")
. - 确保richedit 控件使用正确的窗口类.资源编辑器默认创建一个 RichEdit 2.0.您需要使用文本编辑器手动编辑 .rc 文件,并将
RichEdit20A
或RichEdit20W
替换为RichEdit50W
.W
代表控件的 Unicode 版本. 调用
CRichEditCtrl::StreamIn()
以插入包含超链接的 RTF.下面我提供了一个辅助函数StreamInRtf()
,它简化了将字符串流式传输到控件的任务:
- In the
InitInstance()
method of yourCWinApp
-derived class, callAfxInitRichEdit5()
if your version of Visual Studio supports it. Otherwise callLoadLibraryW(L"msftedit.dll")
. - Make sure the richedit control uses the right window class. The resource editor creates a RichEdit 2.0 by default. You need to manually edit the .rc file using a text editor and replace
RichEdit20A
orRichEdit20W
byRichEdit50W
. TheW
stands for the Unicode version of the control. Call
CRichEditCtrl::StreamIn()
to insert the RTF containing the hyperlink(s). In the following I provide a helper functionStreamInRtf()
that simplifies the task of streaming a string into the control:
struct StreamInRtfCallbackData
{
char const* pRtf;
size_t size;
};
DWORD CALLBACK StreamInRtfCallback( DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb )
{
StreamInRtfCallbackData* pData = reinterpret_cast<StreamInRtfCallbackData*>( dwCookie );
// Copy the number of bytes requested by the control or the number of remaining characters
// of the source buffer, whichever is smaller.
size_t sizeToCopy = std::min<size_t>( cb, pData->size );
memcpy( pbBuff, pData->pRtf, sizeToCopy );
*pcb = sizeToCopy;
pData->pRtf += sizeToCopy;
pData->size -= sizeToCopy;
return 0;
}
DWORD StreamInRtf( CRichEditCtrl& richEdit, char const* pRtf, size_t size = -1, bool selection = false )
{
StreamInRtfCallbackData data;
data.pRtf = pRtf;
data.size = ( size == -1 ? strlen( pRtf ) : size );
EDITSTREAM es;
es.dwCookie = reinterpret_cast<DWORD_PTR>( &data );
es.dwError = 0;
es.pfnCallback = StreamInRtfCallback;
int flags = SF_RTF | ( selection ? SFF_SELECTION : 0 );
richEdit.StreamIn( flags, es );
return es.dwError;
}
示例用法(在此处使用原始字符串文字使 RTF 更具可读性):
Example usage (using a raw string literal here to make the RTF more readable):
StreamInRtf( m_richedit,
R"({tf1
{field{*fldinst {HYPERLINK "https://www.stackoverflow.com" }}{fldrslt {stackoverflow}}}par
Some other textpar
})" );
要处理点击,您需要为 Richedit 控件启用 EN_LINK
通知,例如.g.:
m_richedit.SetEventMask( m_richedit.GetEventMask() | ENM_LINK );
将 EN_LINK
的处理程序添加到您的消息映射:
Add a handler for EN_LINK
to your message map:
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_NOTIFY( EN_LINK, IDC_RICHEDIT1, OnLink )
END_MESSAGE_MAP()
定义事件处理方法来处理鼠标点击和返回键:
Define the event handler method to handle mouse clicks and the return key:
void CMyDialog::OnLink( NMHDR* pnm, LRESULT* pResult )
{
ENLINK* pnml = reinterpret_cast<ENLINK*>( pnm );
if( pnml->msg == WM_LBUTTONDOWN ||
( pnml->msg == WM_KEYDOWN && pnml->wParam == VK_RETURN ) )
{
CString url;
m_richedit.GetTextRange( pnml->chrg.cpMin, pnml->chrg.cpMax, url );
AfxMessageBox( L"URL: "" + url + L""" );
*pResult = 1; // message handled
}
*pResult = 0; // enable default processing
}
从 Windows 8 开始,控件可以显示工具提示,在鼠标光标下显示链接的 URL.可以通过向控件发送 EM_SETEDITSTYLE
消息来启用此功能:
DWORD style = SES_HYPERLINKTOOLTIPS | SES_NOFOCUSLINKNOTIFY;
m_richedit.SendMessage( EM_SETEDITSTYLE, style, style );
如果你错过了定义,这里是:
In case you are missing the defines, here they are:
#ifndef SES_HYPERLINKTOOLTIPS
#define SES_HYPERLINKTOOLTIPS 8
#endif
#ifndef SES_NOFOCUSLINKNOTIFY
#define SES_NOFOCUSLINKNOTIFY 32
#endif
相关文章