20

hereで説明されているように、実行時に TRichEdit を使用して rtf からテキストへの変換を実行する必要があります。私はこれを行うことに成功しましたが、TRichedit.Lines にデータを入力できない場合は、ダミー フォームを親として設定する必要がありました。(エラー: 親が見つかりません)。以下に関数を貼り付けます。親を定義しないようにする方法を誰か提案できますか? これについてコメントして、よりパフォーマンスの高いアイデアを見つけたら教えてください。

注: 出力として 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;

更新: 回答の後、関数を更新し、参照用にここに書き込みます:

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;
4

4 に答える 4

34

TRichEditコントロールは、WindowsのRichEditコントロールのラッパーです。Windowsのコントロールは...まあ..Windowsであり、動作するにはウィンドウハンドルが必要です。Delphiは、ハンドルを作成するためにCreateWindowまたはCreateWindowExを呼び出す必要があり、両方のルーチンが機能するには、有効な親ウィンドウハンドルが必要です。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;
于 2010-07-12T13:49:33.397 に答える
8

これは VCL の機能の一部であり、いくつかの強力な回避策を講じない限り、別の方法で機能させることはできません。ただし、ダミー フォームを親として定義する必要はありません。現在のフォームを使用visible := false;して TRichEdit に設定するだけです。

ただし、本当にパフォーマンスを向上させたい場合は、結果の文字列を作成するために使用しているループを破棄できます。多くのメモリを再割り当てしてコピーする必要があります。TrichEdit.Lines の Text プロパティを使用して各行間の CRLF を取得し、DelimitedText を使用してスペースなどのその他のものを取得します。それらは一度だけ割り当てられる内部バッファを使用します。これにより、大量のテキストを操作している場合、連結がかなり高速化されます。

于 2010-07-12T11:25:35.917 に答える
4

RichEdit コントロールを使用せずに、DrawRichTextを使用して RTF を描画します。(IIRC これはWindowless Rich Edit Controlsと呼ばれます。)変換にもこれを使用できるかもしれませんが、私はこれを試したことはありません。

于 2010-07-12T13:40:28.430 に答える
0

これは、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" を使用しているのは、どういうわけか TStringStream がすべての文字を新しい行に入れるためです。

編集: コードを少し改良し、未使用の変数を削除しました。

于 2014-12-12T10:17:43.903 に答える