Подтвердить что ты не робот

Использование TRichEdit во время выполнения без определения родительского элемента

Мне нужно использовать TRichEdit во время выполнения, чтобы выполнить преобразование rtf в текст, как обсуждалось здесь. Я преуспел в этом, но мне пришлось установить фиктивную форму как родителя, если я не могу заполнить TRichedit.Lines. (Ошибка: родительский отсутствует). Я вставляю свой funciton ниже, может ли кто-нибудь предложить способ избежать определения родителя? Можете ли вы также прокомментировать это и сказать мне, если вы найдете более эффективную идею?

Примечание. Мне нужна строка, а не TStrings как вывод, поэтому она была спроектирована следующим образом.

function RtfToText(const RTF: string;ReplaceLineFeedWithSpace: Boolean): string;
var
  RTFConverter: TRichEdit;
  MyStringStream: TStringStream;
  i: integer;
  CustomLineFeed: string;

begin
  if ReplaceLineFeedWithSpace then
    CustomLineFeed := ' '
    else
    CustomLineFeed := #13;
  try
    RTFConverter := TRichEdit.Create(nil);
    try
      MyStringStream := TStringStream.Create(RTF);
      RTFConverter.parent := Form4; // this is the part I don't like
      RTFConverter.Lines.LoadFromStream(MyStringStream);
      RTFConverter.PlainText := True;
      for i := 0 to RTFConverter.Lines.Count - 1 do
      begin
        if i < RTFConverter.Lines.Count - 1 then
          Result := Result + RTFConverter.Lines[i] + CustomLineFeed
          else
          Result := Result + RTFConverter.Lines[i];
      end;
    finally
      MyStringStream.Free;
    end;
  finally
    RTFConverter.Free;
  end;

end;

UPDATE: После ответа я обновил функцию и напишу ее здесь для справки:

function RtfToText(const RTF: string;ReplaceLineFeedWithSpace: Boolean): string;
var
  RTFConverter: TRichEdit;
  MyStringStream: TStringStream;
begin
  RTFConverter := TRichEdit.CreateParented(HWND_MESSAGE);
  try
    MyStringStream := TStringStream.Create(RTF);
    try
      RTFConverter.Lines.LoadFromStream(MyStringStream);
      RTFConverter.PlainText := True;
      RTFConverter.Lines.StrictDelimiter := True;
      if ReplaceLineFeedWithSpace then
        RTFConverter.Lines.Delimiter := ' '
        else
        RTFConverter.Lines.Delimiter := #13;
      Result := RTFConverter.Lines.DelimitedText;
    finally
      MyStringStream.Free;
    end;
  finally
    RTFConverter.Free;
  end;
end;
4b9b3361

Ответ 1

Элемент управления TRichEdit является оболочкой элемента управления RichEdit в Windows. Элементы управления Windows... хорошо.. Windows, и им нужна ручка Window для работы. Delphi необходимо вызвать CreateWindow или CreateWindowEx для создания дескриптора, и для обеих подпрограмм необходимо иметь действующую родительскую ручку Window Handle. Delphi пытается использовать дескриптор контрольного родителя (и это имеет смысл!). К счастью, можно использовать альтернативный конструктор (конструктор CreateParanted(HWND)), а хорошие люди из Microsoft составили HWND_MESSAGE, который будет использоваться как родительский для окон, которые фактически не нуждаются в "окне" (только для обмена сообщениями).

Этот код работает так, как ожидалось:

procedure TForm2.Button2Click(Sender: TObject);
var R:TRichEdit;
    L:TStringList;
begin
  R := TRichEdit.CreateParented(HWND_MESSAGE);
  try
    R.PlainText := False;
    R.Lines.LoadFromFile('C:\Temp\text.rtf');
    R.PlainText := True;

    Memo1.Lines.Text := R.Lines.Text;
  finally 
    R.Free;
  end;
end;

Ответ 2

Это часть того, как работает VCL, и вы не собираетесь заставить его работать по-другому без каких-либо серьезных обходных решений. Но вам не нужно определять фиктивную форму как родителя; просто используйте свою текущую форму и установите visible := false; на TRichEdit.

Если вы действительно хотите повысить производительность, вы можете выкинуть этот цикл, который вы используете, для построения строки результата. Он должен перераспределять и копировать память. Используйте свойство Text для TrichEdit.Lines, чтобы получить CRLF между каждой строкой и DelimitedText, чтобы получить somethimg else, например пробелы. Они используют внутренний буфер, который выделяется только один раз, что немного ускорит конкатенацию, если вы работаете с большим количеством текста.

Ответ 3

Я использую DrawRichText для рисования RTF без элемента управления RichEdit. (IIRC это называется Windowless Rich Edit Controls.) Возможно, вы также можете использовать это для конвертирования - однако я никогда не пробовал это.

Ответ 4

Это было наиболее полезным для меня, чтобы начать работу с TRichEdit, но не с преобразованием. Однако это работает так, как ожидалось, и вам не нужно устанавливать разделитель строк:

// RTF to Plain:
procedure TForm3.Button1Click(Sender: TObject);
var
    l:TStringList;
    s:WideString;
    RE:TRichEdit;
    ss:TStringStream;
begin
    ss := TStringStream.Create;
    s := Memo1.Text; // Input String
    RE := TRichEdit.CreateParented(HWND_MESSAGE);
    l := TStringList.Create;
    l.Add(s);
    ss.Position := 0;
    l.SaveToStream(ss);
    ss.Position := 0;
    RE.Lines.LoadFromStream(ss);
    Memo2.Text := RE.Text; // Output String
end;

// Plain to RTF:
procedure TForm3.Button2Click(Sender: TObject);
var
    RE:TRichEdit;
    ss:TStringStream;
begin
    RE := TRichEdit.CreateParented(HWND_MESSAGE);
    RE.Text := Memo2.Text; // Input String
    ss := TStringStream.Create;
    ss.Position := 0;
    RE.Lines.SaveToStream(ss);
    ss.Position := 0;
    Memo1.Text := ss.ReadString(ss.Size); // Output String
end;

Я использую TStringList "l" в преобразовании в plain, потому что как-то TStringStream помещает каждый отдельный символ в новую строку.

Изменить: сделал код немного приятнее и удалил неиспользуемые переменные.