在运行时使用 TRichEdit 而不定义父级
我需要在运行时使用 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;
I need to use a TRichEdit at runtime to perform the rtf to text conversion as discussed here. I succeded in doing this but I had to set a dummy form as parent if not I cannot populate the TRichedit.Lines. (Error: parent is missing).
I paste my funciton below, can anyone suggest a way to avoid to define a parent? Can you also comment on this and tell me if you find a more performant idea?
Note: I need a string, not TStrings as output, this is why it has been designed like this.
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:
After the answer I updated the function and write it here for reference:
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
TRichEdit 控件是 Windows 中 RichEdit 控件的包装器。 Windows 的控件是……嗯……Windows,它们需要一个窗口句柄才能工作。 Delphi 需要调用 CreateWindow 或 CreateWindowEx 来创建句柄,并且这两个例程都需要有效的父窗口句柄才能工作。 Delphi 尝试使用控件父级的句柄(这是有道理的!)。幸运的是,我们可以使用另一种构造函数(
CreateParanted(HWND)
构造函数),并且 Microsoft 的优秀人员编写了HWND_MESSAGE
来用作不支持该构造函数的窗口的父窗口。实际上需要一个“窗口”(仅消息传递)。此代码按预期工作:
TRichEdit control is an wrapper around the RichEdit control in Windows. Windows's controls are... well.. Windows, and they need an Window Handle to work. Delphi needs to call CreateWindow or CreateWindowEx to create the Handle, and both routines need an valid parent Window Handle to work. Delphi tries to use the handle of the control's parent (and it makes sense!). Happily one can use an alternative constructor (the
CreateParanted(HWND)
constructor) and the nice people at Microsoft made up theHWND_MESSAGE
to be used as parent for windows that don't actually need a "window" (messaging-only).This code works as expected:
这是 VCL 工作方式的一部分,如果不采取一些繁重的解决方法,您将无法使其以不同的方式工作。但是您不需要定义一个虚拟表单作为父表单;只需使用您当前的表单并在 TRichEdit 上设置
visible := false;
即可。不过,如果您确实想提高性能,则可以丢弃用于构建结果字符串的循环。它必须大量重新分配和复制内存。使用 TrichEdit.Lines 的 Text 属性在每行之间获取 CRLF,并使用 DelimitedText 获取其他内容,例如空格。它们使用仅分配一次的内部缓冲区,如果您正在处理大量文本,这将大大加快串联速度。
This is part of the way the VCL works, and you're not going to get it to work differently without some heavy workarounds. But you don't need to define a dummy form to be the parent; just use your current form and set
visible := false;
on the TRichEdit.If you really want to improve performance, though, you could throw out that loop you're using to build a result string. It has to reallocate and copy memory a lot. Use the Text property of TrichEdit.Lines to get a CRLF between each line, and DelimitedText to get somethimg else, such as spaces. They use an internal buffer that's only allocated once, which will speed up the concatenation quite a bit if you're working with a lot of text.
我使用 DrawRichText 在没有 RichEdit 控件的情况下绘制 RTF。 (IIRC 这称为无窗口富编辑控件.) 也许你也可以用它来转换 - 但我从来没有尝试过这个。
I use DrawRichText to draw RTF without a RichEdit control. (IIRC this is called Windowless Rich Edit Controls.) Maybe you can use this also for converting - however I have never tried this.
这对我开始使用 TRichEdit 来说是最有帮助的,但对转换却没有帮助。然而,这按预期工作,您不需要设置行分隔符:
我在转换为普通文本时使用 TStringList“l”,因为 TStringStream 以某种方式将每个字符放入新行中。
编辑:使代码更好一点并删除未使用的变量。
This has been the most helpfull for me to get started with TRichEdit, but not with the conversion. This however works as expected and you don't need to set the Line Delimiter:
I'm using the TStringList "l" in the conversion to plain because somehow the TStringStream puts every single character in a new line.
Edit: Made the code a bit nicer and removed unused variables.