Loading long RTF text in TRichEdit does not work

If a long RTF sequence (e.g. 150,000 characters) is passed to the TRichEdit control (in XE4), the control does not display text, but instead shows raw RTF code:

 {\rtf1\ansi\ansicpg1252\deff0... 

What's 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 example, with the 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 do not work correctly:

This is what I did:

  • I copied the generated RichEdit1 content (lines 1..15000 with numbers 1..15000) to the notpad.exe file to remove RTF
  • I copied the contents of notepad to RichEdit2

Result:

  • only 12773 lines are displayed. Last line is only 12
  • If I try to add another char to TRichEdit nothing will happen
  • If I delete 10 characters (for each backspace), I can add exactly 10 characters later ...

Is there a hidden character limit for TRichEdit?

+5
source share
2 answers

Advanced editing has a text limitation.

Try using the EM_EXLIMITTEXT message, which sets an upper limit on the size of text that the user can enter or insert into the rich editing control. This message also limits the amount of text you can pass to the rich editing control when streaming RTF ( PlainText = False ). but does not limit control when streaming plain text.

eg:.

 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 implemented in TRichEditStrings.LoadFromFile() : RichEdit.DoSetMaxLength($7FFFFFF0); However, DoSetMaxLength() misused in the sources, as it must be called before the stream loads. In addition, DoSetMaxLength() is not used at all for TRichEditStrings.LoadFromStream() . Remy mentioned this in the comments to his answers.

+5
source

In addition to what kobik said:

TRichEdit.Lines.LoadFromStream() uses EM_STREAMIN internally. If TRichEdit.PlainText is false, LoadFromStream() will first try to load the stream data in RTF format, and if any error occurs, then it will reload the stream data in plain text instead. This is why you see raw RTF code.

RTF is an ASCII-based format, 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 an 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; 
+2
source

Source: https://habr.com/ru/post/1267277/


All Articles