If a long RTF-sequenz (eg 150 000 chars) is streamed into a TRichEdit
control (in XE4), the control does not display the text but instead shows the raw RTF code:
{\rtf1\ansi\ansicpg1252\deff0...
What is wrong?
procedure TForm1.Button1Click(Sender: TObject);
var
RtfText: string;
Stream: TStringStream;
begin
RtfText := GenerateRtfText();
Stream := TStringStream.Create(RtfText);
try
RichEdit2.PlainText := False;
RichEdit2.Lines.LoadFromStream(Stream); //<--- ERROR: RichEdit displays raw RTF-Code
// if RtfText is too long
if StartsText('{\rtf', RichEdit2.Lines.Text) then
begin
ShowMessage('Oh no, not converted!');
//WORKAROUND: 2nd try seems to work...
//Stream.Position := 0;
//RichEdit2.Lines.LoadFromStream(Stream);
end;
finally
Stream.Free;
end;
end;
For instance with following RTF generation function:
function TForm1.GenerateRtfText: string;
var
I: Integer;
Stream: TStringStream;
const
DOES_WORK_COUNT = 10000;
DOES_NOT_WORK_COUNT = 15000;
begin
//Fill
RichEdit1.Lines.BeginUpdate;
try
//for I := 0 to DOES_WORK_COUNT do
for I := 0 to DOES_NOT_WORK_COUNT do
RichEdit1.Lines.Add(IntToStr(I));
finally
RichEdit1.Lines.EndUpdate;
end;
//Convert to RTF
Stream := TStringStream.Create;
try
RichEdit1.Lines.SaveToStream(Stream);
Result := Stream.DataString;
finally
Stream.Free;
end;
end;
Edited: Even copy and paste does not work correctly:
This is what I did:
Result:
12
Is there a hidden character limit for TRichEdit?
Rich edit control has a text limit.
Try using EM_EXLIMITTEXT
message, which sets an upper limit to the amount of text the user can type or paste into a rich edit control. This message also limit the amount of text that you can stream into a rich edit control when streaming RTF (PlainText = False
). but does not limit the control when streaming plain text.
e.g.:
const
RE_MAX_TEXT_SIZE = 256000;
SendMessage(RichEdit1.Handle, EM_EXLIMITTEXT, 0, RE_MAX_TEXT_SIZE);
or:
SendMessage(RichEdit1.Handle, EM_EXLIMITTEXT, 0, $7FFFFFF0);
for the maximum limit as implemented in TRichEditStrings.LoadFromFile()
: RichEdit.DoSetMaxLength($7FFFFFF0);
However, DoSetMaxLength()
is not correctly used in the sources, as it should be called before the stream is loaded. Also, DoSetMaxLength()
is not used at all for TRichEditStrings.LoadFromStream()
. Remy mentioned this in the comments of his answers.
In addition to what kobik said:
TRichEdit.Lines.LoadFromStream()
uses EM_STREAMIN
internally. When TRichEdit.PlainText
is false, LoadFromStream()
will first try to load the stream data as RTF, and if any error is encountered than it will re-load the stream data as plain text instead. That is why you see the raw RTF code appear.
RTF is an ASCII-based format, and so LoadFromStream()
expects 8-bit RTF data (and in the case of PlainText=True
, will try to convert it to Unicode). Try using AnsiString
and TMemoryStream
instead of (Unicode)String
and TStringStream
for your RTF stream.
type
TReadOnlyMemoryBufferStream = class(TCustomMemoryStream)
public
constructor Create(APtr: Pointer; ASize: NativeInt);
function Write(const Buffer; Count: Longint): Longint; override;
end;
constructor TReadOnlyMemoryBufferStream.Create(APtr: Pointer; ASize: NativeInt);
begin
inherited Create;
SetPointer(APtr, ASize);
end;
function TReadOnlyMemoryBufferStream.Write(const Buffer; Count: Longint): Longint;
begin
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
RtfText: AnsiString;
Stream: TReadOnlyMemoryBufferStream;
begin
RtfText := GenerateRtfText();
Stream := TReadOnlyMemoryBufferStream.Create(PAnsiChar(RtfText), Length(RtfText));
try
RichEdit2.PlainText := False;
RichEdit2.Lines.LoadFromStream(Stream);
...
finally
Stream.Free;
end;
end;
function TForm1.GenerateRtfText: AnsiString;
var
I: Integer;
Stream: TMemoryStream;
const
DOES_WORK_COUNT = 10000;
DOES_NOT_WORK_COUNT = 15000;
begin
//Fill
RichEdit1.Lines.BeginUpdate;
try
//for I := 0 to DOES_WORK_COUNT do
for I := 0 to DOES_NOT_WORK_COUNT do
RichEdit1.Lines.Add(IntToStr(I));
finally
RichEdit1.Lines.EndUpdate;
end;
//Convert to RTF
Stream := TMemoryStream.Create;
try
RichEdit1.PlainText := False;
RichEdit1.Lines.SaveToStream(Stream);
SetString(Result, PAnsiChar(Stream.Memory), Stream.Size);
finally
Stream.Free;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With