【问题标题】:Convert HTML to RTF将 HTML 转换为 RTF
【发布时间】:2018-12-23 21:05:58
【问题描述】:

我在数据库中使用 DHtml 组件存储为 html 的注释。但我想将格式更改为 RTF 并改用 DevExpress TcxRichEdit,因为我觉得这是一个更简单的组件,更稳定等。用户会遇到我当然无法重现的消失文本的问题。

TcxRichEdit 工作正常,可以再次保存和加载笔记。 问题是html格式的旧笔记。 我试过this routine,但我从来没有让它工作。 生成了一个 rtf 字符串,但 TcxRichEdit 不接受它。

然后我有了使用剪贴板的想法。 通过将 DHtml 和 TcxRichEdit 并排放置,我应该在它们之间复制和粘贴,然后让剪贴板进行实际转换。在实践中它并不像我想象的那么简单......

这是一些代码:

  function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Boolean;
  begin
    Result := False;
    if (aHtml <> '') and (aHtml <> '&nbsp;') then
    begin
      if not AnsiStartsStr('{\rtf1', aHtml) then
      begin
        vHtmlDlg.InitDoc := aHtml;
        vHtmlDlg.Editor.Stop;
        if vHtmlDlg.Editor.SelectAll then
          if vHtmlDlg.Editor.CutToClipboard then
          begin
            aRichEdit.Clear;
            aRichEdit.PasteFromClipboard;
          end;
      end;

      Result := True;
    end;
  end;

问题是 vHtmlDlg.Editor.SelectAll 总是返回 False。

function TCustomProfDHTMLEdit.SelectAll: Boolean;
const
  CGID_MSHTML: TGUID = '{DE4BA900-59CA-11CF-9592-444553540000}';
var
  D: IDispatch;
  CommandTarget: IOleCommandTarget;
  vaIn, vaOut: OleVariant;
  hr: HRESULT;
begin
  Result := False;
  if GetDOM(D) then
  try
    CommandTarget := D as IOleCommandTarget;
    hr := CommandTarget.Exec(@CGID_MSHTML, 31, OLECMDEXECOPT_DODEFAULT, vaIn, vaOut);
    Result := SUCCEEDED(hr)
  except
  end
end;

返回False的其实是GetDOM:

function TProfDHTMLEdit2.GetDOM(out P: IDispatch): Boolean;
begin
  if Busy then
  begin
    P := nil;
    Result := False
  end
  else
    try
      P := (IDispatch(GetOleObject) as IWebBrowser2).Document;
      Result := True
    except
      P := nil;
      Result := False
    end
end;

不,返回 true 的是 GetBusy...

function TProfDHTMLEdit2.GetBusy: Boolean;
begin
  if FDocumentCompleteReason <> dcrUndefined then
    Result := True
  else
    Result := False
end;

所以我尝试在 html 组件中进行更深入和更深入的挖掘,但我仍然不明白为什么我不能使用 SelectAll。

这是我如何初始化和使用它的简化版本。

  vHtmlDlg := TDhtmlEditorForm.Create(nil);
  vHtmlDlg.Show;
  vHtmlDlg.BrowseMode := False;
  try
   // Call ConvertToRtf with strings in a loop here 
  finally
    vHtmlDlg.Free;
  end;

知道为什么 SelectAll 返回 false 并且不起作用吗?

编辑1: 还有一件事。 html 组件的文档在这里http://www.profgrid.com/documentation/htmledit/ stop 命令似乎停止将 HTML 页面加载到控件中。我偶然使用过,因为在另一个地方它可以防止在 html 中加载数据时发生锁定。无论如何,获得转换并摆脱 HTML 组件真是太好了!

编辑2: 我终于找到了解决方案,而且很简单。只需在设计时将 Dhtml 组件添加到表单中,而不是在代码中创建它。这样,busy 属性是错误的,它可以正常工作。无需在 while 循环中检查忙,因为这是在 SetSource 方法中完成的。我给jachquate 打勾,因为他告诉我该组件是异步的。转换字符串的最终代码如下所示:

  function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Integer;
  begin
    if (aHtml <> '') and (aHtml <> '&nbsp;') then
    begin
      if not AnsiStartsStr('{\rtf1', aHtml) then
      begin
        DhtmlMemo.Source := aHtml;
        if DhtmlMemo.SelectAll then
          if DhtmlMemo.CutToClipboard then
          begin
            aRichEdit.Clear;
            aRichEdit.PasteFromClipboard;
          end;

        if VarIsNull(aRichEdit.EditValue) then
          Result := 0    // Not valid. The caller would delete the note.
        else
          Result := 2;   // String was converted
      end
      else
        Result := 1;     // String already in rtf. Do nothing.
    end
    else
      Result := 0;       
  end;

感谢您对我的问题的支持和承诺!

【问题讨论】:

    标签: html delphi rtf


    【解决方案1】:

    由于这是一次性转换,我同意您使用剪贴板。

    HTML 组件看起来像一种 Async 组件,因此您必须等待,因为它会在其他线程中处理加载/表示提供的 HTML,所有这些都由组件封装。我不知道具体的组件,但我敢打赌这会起作用:

      function _ConvertToRtf(aHtml: String; aRichEdit: TcxRichEdit): Boolean;
      begin
        Result := False;
        if (aHtml <> '') and (aHtml <> '&nbsp;') then
        begin
          if not AnsiStartsStr('{\rtf1', aHtml) then
          begin
            vHtmlDlg.InitDoc := aHtml;
            vHtmlDlg.Editor.Stop;
            //before or after stop, I'm not sure what stop means
            while vHtmlDlg.Busy do
              Sleep(1); // or maybe Application.ProcessMessages, try both
            if vHtmlDlg.Editor.SelectAll then
              if vHtmlDlg.Editor.CutToClipboard then
              begin
                aRichEdit.Clear;
                aRichEdit.PasteFromClipboard;
                Result := True;  //of course you return true only if this succeeds.
              end;
          end;
        end;
      end;
    

    如果这是在用户计算机上进行的多次转换,请阅读@Chris answer

    【讨论】:

    • 是的,大约700个html-strings需要转换成RTF格式。手动操作有点无聊....
    • 它不在用户机器上。它位于连接了许多用户的服务器上。因此,当使用新的 Richedit 组件更改版本时,我会运行一个在数据库中进行转换的维护方法。之后用户就可以登录了。
    • @Roland,你试过我的建议了吗?在我看来,您必须摆脱 stop 方法并等待(如建议的那样)直到组件不再忙
    • 虽然您可以让它在忙碌睡眠时使用,但我宁愿编写一个类并挂钩相关的 WebBrowser 事件
    • @Daniel,请记住这是数百(数千?)记录的一次转换,恕我直言,省力的解决方案是最好的,因为性能或正确性并不是最重要的。
    【解决方案2】:

    如果您在剪切/复制之后、粘贴之前进行延迟,您可能会有机会。 但总的来说,像这样使用剪贴板是非常糟糕的做法。提供剪贴板是为了方便用户,而不是程序员。任何可识别剪贴板的程序都会对此做出反应,包括任何远程桌面/citrix 会话,它们将试图通过网络发送这些垃圾。

    【讨论】:

    • 我假设他正在编写一个小型“转换器”应用程序,他将运行一次,因此与其他应用程序的干扰不是问题
    猜你喜欢
    • 2010-10-01
    • 1970-01-01
    • 2014-11-15
    • 2012-02-17
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    相关资源
    最近更新 更多