Loading long RTF-Text in TRichEdit does not work

匿名 (未验证) 提交于 2019-12-03 01:20:02

问题:

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:

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

Result:

  • only 12773 lines are displayed correctly. The last line is only 12
  • if I try to add another char into the TRichEdit nothing happens
  • if I remove 10 chars (per backspace) I can add exactly 10 chars afterwards...

Is there a hidden character limit for TRichEdit?

回答1:

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.



回答2:

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; 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!