Board index » delphi » RichEdit: SelStart, Lines.Text & WordWrap incompatibility

RichEdit: SelStart, Lines.Text & WordWrap incompatibility

Hi,

There is a problem in TRichEdit involving SelStart and Lines.Text when
WordWrap is true. Examine the following code, using a

RichEdit with default dimensions of 185x89 pixels (the full code is
pasted at the bottom of this document):

const
   SomeText = 'Text to be selected';

   with RichEdit1 do
   begin
     lines.clear;
     lines.add('Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam
Spam Spam Spam Spam Spam Spam');
     lines.add(SomeText);
     lines.add('ooooooooooooooooooooooooooooooooooo');
   end;

On my computer (Windows XP & Delphi 6.0), the lines (TStrings) property
will contain 5 items:

"Spam Spam Spam Spam Spam Spam "
"Spam Spam Spam Spam Spam Spam "
"Spam Spam Spam Spam Spam"
"Text to be selected"
"ooooooooooooooooooooooooooooo"
"oooooo"

The large spamspamspam line has been word wrapped twice. The lines.text
property will then be:

"Spam Spam Spam Spam Spam Spam <crlf>Spam Spam Spam Spam Spam Spam
<crlf>Spam Spam Spam Spam Spam<crlf>Text to be

selected<crlf>ooooooooooooooooooooooooooooo<crlf>oooooo<crlf>"

<crlf> = carriage return + linefeed (#13#10).

Now if you:

   with RichEdit1 do
   begin
     SelStart := pos(SomeText, Lines.Text) - 1;
     SelLength := Length(SomeText);
     SetFocus;
   end;

SelStart will be 4 bytes too large. These 4 bytes correspond to two
CRLF's because of the two word wraps. The selected text

will start at the space after "Text" and end after the first two o's. If
there would be 3 word wraps, the selected text

would be 6 bytes too far. Using lines or lines.text is not useful
because one cannot distinguish between a word wrap or an

end-of-line.

I've written a routine GetRichEditLines(ARichEdit: TRichEdit; var
AString: string) which returns the control's contents

without the wordwrap CRLF's. The routine returns:

"Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam
Spam Spam

Spam<crlf>SomeText<crlf>ooooooooooooooooooooooooooooooooooo<crlf>"

Now with:

   GetRichEditLines(RichEdit1, TheLines);
   with RichEdit1 do
   begin
     SelStart := pos(SomeText, TheLines) - 1;
     SelLength := Length(SomeText);
     SetFocus;
   end;

The correct text is selected.

The code to a demo program is pasted below. If anyone can find a
possible problem with GetRichEditLines, please let me know.

Also, does anyone know what value for CodePage in TGetTextEx,
TGetTextLengthEx variables needs to be used?

Thanks,
Willy Angenent

-------------------------------------------------------------------

Add a RichEdit control and 3 buttons to the form with the names:

     RichEdit1: TRichEdit;
     ButtonPutText: TButton;
     ButtonSelText1: TButton;
     ButtonSelText2: TButton;

Don't forget the 'uses RichEdit';

The unit's source:
-----------

unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
   Dialogs, StdCtrls, ComCtrls;

type
   TForm1 = class(TForm)
     ButtonPutText: TButton;
     RichEdit1: TRichEdit;
     ButtonSelText1: TButton;
     ButtonSelText2: TButton;
     procedure ButtonPutTextClick(Sender: TObject);
     procedure ButtonSelText1Click(Sender: TObject);
     procedure ButtonSelText2Click(Sender: TObject);
   private
     { Private declarations }
   public
     { Public declarations }
   end;

var
   Form1: TForm1;

implementation

uses RichEdit;

{$R *.dfm}

const
   SomeText = 'Text to be selected';

procedure GetRichEditLines(ARichEdit: TRichEdit; var AString: string);
var
   Length: integer;
   GetTextEx: TGetTextEx;
   GetTextLengthEx: TGetTextLengthEx;

begin
   GetTextLengthEx.flags := GT_DEFAULT;
   GetTextLengthEx.codepage := CP_ACP;

   length := SendMessage(ARichEdit.Handle, EM_GETTEXTLENGTHEX,
WParam(@GetTextLengthEx), 0);

   // For some reason "length + 1" needs to be requested, not "length"
... ??
   GetTextEx.cb := length + 1;
   GetTextEx.flags := GT_DEFAULT;
   GetTextEx.codepage := CP_ACP;
   GetTextEx.lpDefaultChar := nil;
   GetTextEx.lpUsedDefChar := Pointer(false);

   SetLength(AString, Length + 1);
   Length := SendMessage(ARichEdit.Handle, EM_GETTEXTEX,
WParam(@GetTextEx), LongInt(PChar(AString)));
   SetLength(AString, Length);
end;

procedure TForm1.ButtonPutTextClick(Sender: TObject);
begin
   with RichEdit1 do
   begin
     lines.clear;
     lines.add('Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam Spam
Spam Spam Spam Spam Spam Spam');
     lines.add(SomeText);
     lines.add('ooooooooooooooooooooooooooooooooooo');
   end;
end;

procedure TForm1.ButtonSelText1Click(Sender: TObject);
begin
   with RichEdit1 do
   begin
     SelStart := pos(SomeText, Lines.Text) - 1;
     SelLength := Length(SomeText);
     SetFocus;
   end;
end;

procedure TForm1.ButtonSelText2Click(Sender: TObject);
var
   TheLines: string;

begin
   GetRichEditLines(RichEdit1, TheLines);
   with RichEdit1 do
   begin
     SelStart := pos(SomeText, TheLines) - 1;
     SelLength := Length(SomeText);
     SetFocus;
   end;
end;

end.

 

Re:RichEdit: SelStart, Lines.Text & WordWrap incompatibility


Quote
In article <3e207...@newsgroups.borland.com>, Willy Angenent wrote:
> There is a problem in TRichEdit involving SelStart and Lines.Text when
> WordWrap is true. Examine the following code, using a

You have made an error in using Lines.Text. Use richedit1.Text and you get
the text without hard linebreaks at the places were the controls wraps the
text. Lines.Text inherits the mechanism used to build the Text from
TStrings, and that actually walks sequenctially over all lines and adds
them together, with a hard linebreak at the end of each line.

Applies to TMemo as well, by the way.

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be

Re:RichEdit: SelStart, Lines.Text & WordWrap incompatibility


Ahhhhhh! I hadn't found the text property in the help or in newsgroups.
  Thanks for your answer.
Quote
Peter Below (TeamB) wrote:
> In article <3e207...@newsgroups.borland.com>, Willy Angenent wrote:

>>There is a problem in TRichEdit involving SelStart and Lines.Text when
>>WordWrap is true. Examine the following code, using a

> You have made an error in using Lines.Text. Use richedit1.Text and you get
> the text without hard linebreaks at the places were the controls wraps the
> text. Lines.Text inherits the mechanism used to build the Text from
> TStrings, and that actually walks sequenctially over all lines and adds
> them together, with a hard linebreak at the end of each line.

> Applies to TMemo as well, by the way.

> --
> Peter Below (TeamB)  
> Use the newsgroup archives :
> http://www.mers.com/searchsite.html
> http://www.tamaracka.com/search.htm
> http://groups.google.com
> http://www.prolix.be

Re:RichEdit: SelStart, Lines.Text & WordWrap incompatibility


In article <3e219...@newsgroups.borland.com>, Willy Angenent

Quote
<Willy.Angen...@N0SPAMwxs.nl> wrote:
> Ahhhhhh! I hadn't found the text property in the help or in newsgroups.
>   Thanks for your answer.

Well having sorted that out, you might also want to know that accessing
RichEdit.Text causes a copy of potentially a very string and should usually
be avoided if possible for speed and efficiency.

Have a look at the RichEdit method FindText.
That may do what you want.

-Iain.

Other Threads