delphi - Uso de TRichEdit en tiempo de ejecución sin definir un padre
rtf (4)
El control TRichEdit es una envoltura alrededor del control RichEdit en Windows. Los controles de Windows son ... bueno ... Windows, y necesitan un identificador de Windows para funcionar. Delphi necesita llamar a CreateWindow o CreateWindowEx para crear el identificador, y ambas rutinas necesitan un identificador de ventana principal válido para funcionar. Delphi intenta usar el controlador de los padres del control (¡y tiene sentido!). Felizmente, uno puede usar un constructor alternativo (el constructor CreateParanted(HWND)
) y la gente agradable de Microsoft creó el HWND_MESSAGE
para ser usado como padre para ventanas que en realidad no necesitan una "ventana" (solo mensajes).
Este código funciona como se espera:
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;
Necesito usar un TRichEdit en tiempo de ejecución para realizar la conversión de rtf a texto como se explica here . Logré hacer esto, pero tuve que establecer una forma ficticia como padre; de lo contrario, no puedo rellenar el TRichedit.Lines. (Error: falta el padre). Pego mi función a continuación, ¿alguien puede sugerir una forma de evitar definir un padre? ¿Puedes también comentar sobre esto y decirme si encuentras una idea más interesante?
Nota: Necesito una cadena, no TStrings como salida, es por eso que ha sido diseñado de esta manera.
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;
ACTUALIZACIÓN : Después de la respuesta actualicé la función y la escribo aquí para referencia:
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;
Esto es parte de la forma en que funciona el VCL, y no va a lograr que funcione de manera diferente sin algunas soluciones pesadas. Pero no es necesario definir una forma ficticia para ser el padre; solo usa tu formulario actual y configura visible := false;
en el TRichEdit.
Sin embargo, si realmente desea mejorar el rendimiento, puede tirar ese bucle que está usando para crear una cadena de resultados. Tiene que reasignar y copiar mucho la memoria. Use la propiedad Text de TrichEdit.Lines para obtener un CRLF entre cada línea y DelimitedText para obtener otra cosa, como espacios. Utilizan un búfer interno que solo se asigna una vez, lo que acelerará bastante la concatenación si se trabaja con mucho texto.
Esto ha sido lo más útil para comenzar con TRichEdit, pero no con la conversión. Sin embargo, esto funciona como se esperaba y no es necesario configurar el delimitador de línea:
// 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;
Estoy usando TStringList "l" en la conversión a simple porque, de alguna manera, TStringStream coloca todos los caracteres en una nueva línea.
Editar: hizo el código un poco más agradable y eliminó las variables no utilizadas.
Uso DrawRichText para dibujar RTF sin un control RichEdit. (IIRC, esto se denomina Controles de edición enriquecidos sin ventanas ). Tal vez también pueda usar esto para convertir, sin embargo, nunca lo he intentado.