Конвертировать HTML в RTF

3

У меня есть записи в базе данных, хранящиеся как html с компонентом DHtml. Но я хочу изменить формат RTF и использовать DevExpress TcxRichEdit вместо этого, потому что я чувствую, что это более простой компонент, более стабильный и т.д. У пользователей возникают проблемы с исчезающими текстами, которые я, конечно, не могу воспроизвести.

TcxRichEdit работает нормально и может сохранять и загружать заметки снова. Проблема заключается в старых заметках в формате html. Я пробовал эту процедуру, но я так и не получил ее на работу. Строка 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/ Команда остановки, похоже, перестает загружать HTML-страницу в элемент управления. Я использовал случайно, потому что в другом месте он предотвращает блокировку при загрузке данных в html. В любом случае было бы очень приятно получить преобразование и избавиться от HTML-компонента!

Edit2: Я нашел решение наконец, и это было довольно просто. Просто добавьте компонент Dhtml в форму во время разработки вместо того, чтобы создавать его в коде. Таким образом, занятое свойство было ложным, и оно просто работает. Нет необходимости проверять занятость в цикле 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;

Спасибо за поддержку и приверженность моей проблеме!

Теги:
rtf

2 ответа

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.

  • 0
    Да, это около 700 html-строк, которые необходимо преобразовать в формат RTF. Немного скучно делать это вручную ....
  • 0
    И это не на машине пользователей. Это на сервере, к которому подключено много пользователей. Поэтому, когда версия изменяется с новым компонентом Richedit, я запускаю метод обслуживания, который выполняет преобразование в базе данных. После этого пользователи могут войти.
Показать ещё 3 комментария
2

У вас может быть шанс, если вы положите задержку после вырезания/копирования перед пастой. Но в целом использование такого буфера обмена очень плохое. Буфер обмена предоставляется для удобства пользователя, а не для программиста. Любые программы, ориентированные на буфер обмена, будут реагировать на это, включая любые сеансы удаленного рабочего стола /citrix, которые будут пытаться перекачивать эту информацию по сети.

  • 0
    Я предполагаю, что он пишет небольшое «конвертерное» приложение, которое он собирается запустить один раз, поэтому вмешательство в другие приложения не является проблемой

Ещё вопросы

Сообщество Overcoder
Наверх
Меню