我的RichEdit Control可以包含可点击的链接吗?

Aj *_*nez 1 c++ winapi mfc visual-studio-2010

我想在Edit Control或Rich Edit 2.0 Control中显示一系列字符串.之后,我希望显示的部分文字带下划线和蓝色.然后可以单击这些带下划线的文本以打开另一个对话框或某种对话框.

有没有办法做到这一点?

zet*_*t42 7

Rich Edit 2.0仅支持自动RichEdit超链接,而Rich Edit 4.1和更高版本(msftedit.dll)支持友好名称超链接.

可以使用CFE_LINKCFE_HIDDEN 字符格式标记的组合在Rich Edit 2.0中模拟友好名称超链接.使用标记文本CFE_LINK并通过应用隐藏URL CFE_HIDDEN.处理EN_LINK通知以对点击作出反应.此时,您必须进行一些解析以从富文本中提取隐藏的URL.

或者,只需使用CFE_LINK文本并使用a std::map将文本映射到URL.只要文本到URL的1:1映射,这将起作用.

编辑:我刚刚注意到你只想在点击一个链接时"打开另一个对话框",所以CFE_LINK在你的情况下应用就足够了.

编辑2:如果您不需要显示格式化文本而且您也不需要滚动,我建议使用SysLink控件.SysLink控件显示的链接比RichEdit控件中的链接具有更好的可访问性.前者支持在TAB单个链接中导航的关键,而后者则不支持.

实现友好名称超链接(Rich Edit 4.1+)

免责声明:以下代码已在Win 10下通过创建者更新进行了测试.我还没有时间在旧的操作系统版本下测试它.

  • InitInstance()您的CWinApp-derived类的方法中,AfxInitRichEdit5()如果您的Visual Studio版本支持它,请调用它.否则打电话LoadLibraryW(L"msftedit.dll").
  • 确保richedit控件使用正确的窗口类.资源编辑器默认创建RichEdit 2.0.您需要使用文本编辑器手动编辑.rc文件并替换RichEdit20ARichEdit20W使用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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    示例用法(在此使用原始字符串文字使RTF更具可读性):

    StreamInRtf( m_richedit, 
    R"({\rtf1
    {\field{\*\fldinst {HYPERLINK "https://www.stackoverflow.com" }}{\fldrslt {stackoverflow}}}\par
    Some other text\par
    })" );
    
    Run Code Online (Sandbox Code Playgroud)
  • 要处理点击,您需要EN_LINK为richedit控件启用通知,例如:

    m_richedit.SetEventMask( m_richedit.GetEventMask() | ENM_LINK );
    
    Run Code Online (Sandbox Code Playgroud)

    EN_LINK您的消息映射添加处理程序:

    BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
        ON_NOTIFY( EN_LINK, IDC_RICHEDIT1, OnLink )
    END_MESSAGE_MAP()
    
    Run Code Online (Sandbox Code Playgroud)

    定义事件处理程序方法以处理鼠标单击和返回键:

    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
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 从Windows 8开始,控件可以显示工具提示,显示鼠标光标下的链接的URL.可以通过将EM_SETEDITSTYLE消息发送到控件来启用此功能:

    DWORD style = SES_HYPERLINKTOOLTIPS | SES_NOFOCUSLINKNOTIFY;
    m_richedit.SendMessage( EM_SETEDITSTYLE, style, style );
    
    Run Code Online (Sandbox Code Playgroud)

    如果您缺少定义,这里它们是:

    #ifndef SES_HYPERLINKTOOLTIPS
        #define SES_HYPERLINKTOOLTIPS   8
    #endif
    #ifndef SES_NOFOCUSLINKNOTIFY
        #define SES_NOFOCUSLINKNOTIFY   32
    #endif 
    
    Run Code Online (Sandbox Code Playgroud)