Использование 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;
Ответы
Ответ 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 помещает каждый отдельный символ в новую строку.
Изменить: сделал код немного приятнее и удалил неиспользуемые переменные.