我想在Edit Control或Rich Edit 2.0 Control中显示一系列字符串。之后,我希望显示的部分文字带下划线和蓝色。然后可以单击这些带下划线的文本打开另一个对话框或某种对话框。
有办法做到这一点吗?
答案 0 :(得分:6)
Rich Edit 2.0仅支持Automatic RichEdit Hyperlinks,而Rich Edit 4.1和更新版本(msftedit.dll)支持Friendly Name Hyperlinks。
您可以使用CFE_LINK
和CFE_HIDDEN
character formatting flags的组合,在Rich Edit 2.0中模拟友好名称超链接。使用CFE_LINK
标记文字,并通过应用CFE_HIDDEN
隐藏网址。处理EN_LINK
通知以对点击做出反应。此时,您必须进行一些解析以从富文本中提取隐藏的URL。
或者,只需对文本使用CFE_LINK
,然后使用std::map
将文本映射到网址。只要文本到URL的1:1映射,这将有效。
修改:我刚刚注意到您只想在点击链接时“打开另一个对话框”,因此在您的情况下应用CFE_LINK
应该足够了。
编辑2:如果您不需要显示格式化文本而且您也不需要滚动,我建议您使用SysLink control。 SysLink控件显示的链接比RichEdit控件中的链接具有更好的可访问性。前者支持 TAB 键来浏览单个链接,而后者则不支持。
免责声明:以下代码已在Win 10下经过创作者更新测试。我还没有时间在较旧的操作系统版本下测试它。
InitInstance()
派生类的CWinApp
方法中,如果您的Visual Studio版本支持,请调用AfxInitRichEdit5()
。否则请致电LoadLibraryW(L"msftedit.dll")
。RichEdit20A
或RichEdit20W
替换为RichEdit50W
。 W
代表控件的Unicode版本。调用CRichEditCtrl::StreamIn()
插入包含超链接的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.stackoverflow.com" }}{\fldrslt {stackoverflow}}}\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()
定义事件处理程序方法以处理鼠标点击和返回键:
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 );
如果你缺少定义,这里它们是:
#ifndef SES_HYPERLINKTOOLTIPS
#define SES_HYPERLINKTOOLTIPS 8
#endif
#ifndef SES_NOFOCUSLINKNOTIFY
#define SES_NOFOCUSLINKNOTIFY 32
#endif