Loading long RTF-Text in TRichEdit does not work

╄→гoц情女王★ 提交于 2019-12-10 14:33:18

问题


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;


来源:https://stackoverflow.com/questions/43679369/loading-long-rtf-text-in-trichedit-does-not-work

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