我想在编辑控件或富文本2.0控件中显示一系列字符串。之后,我希望显示的一些文本被下划线并呈蓝色。这些下划线的文本可以点击以打开另一个对话框或某种形式的内容。
是否有方法实现此功能?
我想在编辑控件或富文本2.0控件中显示一系列字符串。之后,我希望显示的一些文本被下划线并呈蓝色。这些下划线的文本可以点击以打开另一个对话框或某种形式的内容。
是否有方法实现此功能?
富文本编辑器 2.0 仅支持 自动富文本超链接, 而富文本编辑器 4.1 及更新版本(msftedit.dll)支持 友好名称超链接。
您可以通过使用组合 CFE_LINK
和 CFE_HIDDEN
字符格式标志 来在富文本编辑器 2.0 中模拟友好名称超链接。使用 CFE_LINK
对文本进行标记,并通过应用 CFE_HIDDEN
隐藏 URL。 处理 EN_LINK
通知以响应单击事件。此时,您需要进行一些解析操作来从富文本中提取隐藏的 URL。
或者,只需使用 CFE_LINK
进行文本标记,并使用 std::map
将文本映射到 URL。 只要文本与 URL 的映射关系为 1:1,则可以正常工作。
编辑:我注意到你只是想在单击链接时“打开另一个对话框”,所以在你的情况下,只应用CFE_LINK
就足够了。
编辑2:如果您不需要显示格式化文本,也不需要滚动条,我建议使用SysLink control。由SysLink控件显示的链接比RichEdit控件中的链接更易于访问。前者支持TAB键浏览各个链接,而后者则不支持。
免责声明:以下代码已在Win 10上进行过测试,具有创作者更新。我还没有找到时间在旧的操作系统版本下测试它。
InitInstance()
method of your CWinApp
-derived class, call AfxInitRichEdit5()
if your version of Visual Studio supports it. Otherwise call LoadLibraryW(L"msftedit.dll")
.RichEdit20A
or RichEdit20W
by RichEdit50W
. The W
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 function StreamInRtf()
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;
}
Example usage (using a raw string literal here to make the RTF more readable):
StreamInRtf( m_richedit,
R"({\rtf1
{\field{\*\fldinst {HYPERLINK "https://www.stackoverflow.com" }}{\fldrslt {stackoverflow}}}\par
Some other text\par
})" );
To handle clicks you need to enable EN_LINK
notifications for the richedit control, e. g.:
m_richedit.SetEventMask( m_richedit.GetEventMask() | ENM_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
}
Beginning with Windows 8, the control can show a tooltip that displays the URL of the link under the mouse cursor. This feature can be enabled by sending the EM_SETEDITSTYLE
message to the control:
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