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