我的 RichEdit 控件可以包含可点击的链接吗?
Can my RichEdit Control contain clickable links?
我想向编辑控件或 Rich Edit 2.0 控件显示一系列字符串。之后,我希望显示的一些文本带有下划线和蓝色。然后可以单击这些带下划线的文本以打开另一个对话框或某种类型。
有办法吗?
Rich Edit 2.0 仅支持Automatic RichEdit Hyperlinks while Rich Edit 4.1 and newer (msftedit.dll) supports Friendly Name Hyperlinks。
您可以通过结合使用 CFE_LINK
和 CFE_HIDDEN
[=] 在 Rich Edit 2.0 中模拟友好名称 hyperlinks 39=] 对点击做出反应的通知。此时,您将不得不进行一些解析以从富文本中提取隐藏的 URL。
或者只使用 CFE_LINK
作为文本并使用 std::map
将文本映射到 URL。只要有文本到 URL.
的 1:1 映射,这就会起作用
编辑: 我刚刚注意到当单击 link 时您只需要 "to open another dialog",所以只应用 CFE_LINK
应该很好对你来说足够了。
编辑2:如果你不需要显示格式化文本,也不需要滚动,我建议使用SysLink control。 SysLink 控件显示的链接比 RichEdit 控件中的 links 具有更好的可访问性。前者支持 TAB 键在各个 link 中导航,而后者不支持。
实施友好名称 Hyperlinks(Rich Edit 4.1+)
免责声明:以下代码已在 Win 10 下进行测试,并更新了 creators。我还没有时间在旧 OS 版本下测试它。
- 在
CWinApp
派生的 class 的 InitInstance()
方法中,如果您的 Visual Studio 版本支持,请调用 AfxInitRichEdit5()
。否则调用 LoadLibraryW(L"msftedit.dll")
.
- 确保richedit控件使用正确windowclass。资源编辑器默认创建一个 RichEdit 2.0。您需要使用文本编辑器手动编辑 .rc 文件,并将
RichEdit20A
或 RichEdit20W
替换为 RichEdit50W
。 W
代表控件的 Unicode 版本。
调用 CRichEditCtrl::StreamIn()
插入包含 hyperlink(s) 的 RTF。在下文中,我提供了一个辅助函数 StreamInRtf()
,它简化了将字符串流式传输到控件中的任务:
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 更具可读性):
StreamInRtf( m_richedit,
R"({\rtf1
{\field{\*\fldinst {HYPERLINK "https://www.whosebug.com" }}{\fldrslt {Whosebug}}}\par
Some other text\par
})" );
要处理点击,您需要为 richedit 控件启用 EN_LINK
通知,例如。 g.:
m_richedit.SetEventMask( m_richedit.GetEventMask() | ENM_LINK );
将 EN_LINK
的处理程序添加到您的消息映射:
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_NOTIFY( EN_LINK, IDC_RICHEDIT1, OnLink )
END_MESSAGE_MAP()
定义事件处理方法来处理鼠标点击和 return 键:
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
}
从Windows8开始,控件可以显示工具提示,在鼠标光标下显示link的URL。可以通过向控件发送 EM_SETEDITSTYLE
消息来启用此功能:
DWORD style = SES_HYPERLINKTOOLTIPS | SES_NOFOCUSLINKNOTIFY;
m_richedit.SendMessage( EM_SETEDITSTYLE, style, style );
如果您缺少定义,它们是:
#ifndef SES_HYPERLINKTOOLTIPS
#define SES_HYPERLINKTOOLTIPS 8
#endif
#ifndef SES_NOFOCUSLINKNOTIFY
#define SES_NOFOCUSLINKNOTIFY 32
#endif
我想向编辑控件或 Rich Edit 2.0 控件显示一系列字符串。之后,我希望显示的一些文本带有下划线和蓝色。然后可以单击这些带下划线的文本以打开另一个对话框或某种类型。
有办法吗?
Rich Edit 2.0 仅支持Automatic RichEdit Hyperlinks while Rich Edit 4.1 and newer (msftedit.dll) supports Friendly Name Hyperlinks。
您可以通过结合使用 CFE_LINK
和 CFE_HIDDEN
[=] 在 Rich Edit 2.0 中模拟友好名称 hyperlinks 39=] 对点击做出反应的通知。此时,您将不得不进行一些解析以从富文本中提取隐藏的 URL。
或者只使用 CFE_LINK
作为文本并使用 std::map
将文本映射到 URL。只要有文本到 URL.
编辑: 我刚刚注意到当单击 link 时您只需要 "to open another dialog",所以只应用 CFE_LINK
应该很好对你来说足够了。
编辑2:如果你不需要显示格式化文本,也不需要滚动,我建议使用SysLink control。 SysLink 控件显示的链接比 RichEdit 控件中的 links 具有更好的可访问性。前者支持 TAB 键在各个 link 中导航,而后者不支持。
实施友好名称 Hyperlinks(Rich Edit 4.1+)
免责声明:以下代码已在 Win 10 下进行测试,并更新了 creators。我还没有时间在旧 OS 版本下测试它。
- 在
CWinApp
派生的 class 的InitInstance()
方法中,如果您的 Visual Studio 版本支持,请调用AfxInitRichEdit5()
。否则调用LoadLibraryW(L"msftedit.dll")
. - 确保richedit控件使用正确windowclass。资源编辑器默认创建一个 RichEdit 2.0。您需要使用文本编辑器手动编辑 .rc 文件,并将
RichEdit20A
或RichEdit20W
替换为RichEdit50W
。W
代表控件的 Unicode 版本。 调用
CRichEditCtrl::StreamIn()
插入包含 hyperlink(s) 的 RTF。在下文中,我提供了一个辅助函数StreamInRtf()
,它简化了将字符串流式传输到控件中的任务: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 更具可读性):
StreamInRtf( m_richedit, R"({\rtf1 {\field{\*\fldinst {HYPERLINK "https://www.whosebug.com" }}{\fldrslt {Whosebug}}}\par Some other text\par })" );
要处理点击,您需要为 richedit 控件启用
EN_LINK
通知,例如。 g.:m_richedit.SetEventMask( m_richedit.GetEventMask() | ENM_LINK );
将
EN_LINK
的处理程序添加到您的消息映射:BEGIN_MESSAGE_MAP(CMyDialog, CDialog) ON_NOTIFY( EN_LINK, IDC_RICHEDIT1, OnLink ) END_MESSAGE_MAP()
定义事件处理方法来处理鼠标点击和 return 键:
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 }
从Windows8开始,控件可以显示工具提示,在鼠标光标下显示link的URL。可以通过向控件发送
EM_SETEDITSTYLE
消息来启用此功能:DWORD style = SES_HYPERLINKTOOLTIPS | SES_NOFOCUSLINKNOTIFY; m_richedit.SendMessage( EM_SETEDITSTYLE, style, style );
如果您缺少定义,它们是:
#ifndef SES_HYPERLINKTOOLTIPS #define SES_HYPERLINKTOOLTIPS 8 #endif #ifndef SES_NOFOCUSLINKNOTIFY #define SES_NOFOCUSLINKNOTIFY 32 #endif