【问题标题】:Can my RichEdit Control contain clickable links?我的 RichEdit 控件可以包含可点击的链接吗?
【发布时间】:2018-01-04 01:58:09
【问题描述】:

我想向编辑控件或 Rich Edit 2.0 控件显示一系列字符串。之后,我希望显示的一些文本带有下划线和蓝色。然后可以单击这些带下划线的文本以打开另一个对话框或某种对话框。

有没有办法做到这一点?

【问题讨论】:

    标签: c++ visual-studio-2010 winapi mfc


    【解决方案1】:

    Rich Edit 2.0 仅支持 Automatic RichEdit Hyperlinks,而 Rich Edit 4.1 及更高版本 (msftedit.dll) 支持 Friendly Name Hyperlinks

    可以通过使用CFE_LINKCFE_HIDDEN character formatting flags 的组合来模拟Rich Edit 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 键来浏览各个链接,而后者不支持。

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

    免责声明:以下代码已在 Win 10 下测试,并带有创作者更新。我还没有时间在旧操作系统版本下测试它。

    • 在您的CWinApp 派生类的InitInstance() 方法中,如果您的Visual Studio 版本支持,请调用AfxInitRichEdit5()。否则请致电LoadLibraryW(L"msftedit.dll")
    • 确保richedit 控件使用正确的窗口类。资源编辑器默认创建一个 RichEdit 2.0。您需要使用文本编辑器手动编辑 .rc 文件并将RichEdit20ARichEdit20W 替换为RichEdit50WW 代表控件的 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 
      

    【讨论】:

    • 一旦我弄清楚如何将文本附加到我的 Richeditbox...
    • 我需要实际格式化文本 - 不同的颜色。它也将是一个生成的列表。
    • 我在普通的 WinAPI 中实现了基本相同的功能。 Win 10 完美运行,包括超链接自动工具提示。 Win 7 有点奇怪:文本中没有突出显示链接,但它可以工作!即光标变为“手”,并发送通知。不支持工具提示。
    • @lariona 已确认。对于 Win 7,您必须设置链接的格式,以便它实际上看起来像一个链接。
    • 通过EM_SETTEXTEX 消息从 RTF 字符串设置文本的更简单替代方法(必须有一个 MFC 等效项,但我不是这里的专家)。它从富文本中识别纯文本,并且不需要任何回调例程。 EM_STREAMIN (CRichEditCtrl::StreamIn) 可能主要用于读取文件。
    猜你喜欢
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多