将HTML转换为RTF

时间:2011-03-25 14:35:38

标签: html delphi rtf

我在数据库中记录了使用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;

实际上GetDOM返回False:

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;

不,GetBusy返回true ...

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并且不起作用?

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

EDIT2: 我终于找到了解决方案而且非常简单。只需在设计时将Dhtml组件添加到表单中,而不是在代码中创建它。这样繁忙的财产是错误的,它只是工作。没有必要在while循环中检查busy,因为这是在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;

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

由于这是一次性转换,我和你在一起使用剪贴板。

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