Having some trouble with EM_CHARFROMPOS to get index of character in a TRichEdit

Hi Experts, I want to be able to hove the mouse cursor over a specific character in a TRichEdit and have a hint appear displaying simply the index of that particular character within the TRichEdit. Googling around I found some Delphi samples using the EM_CHARFROMPOS call and have implemented something in the "MouseMove" event that *almost* works right, but not quite. The only real problem I'm having with it is if I hover the mouse cursor at empty white space at the far right (unused portion) of the TRichEdit, it still returns the index as the 1st character (ie. index = 0). In this case, I'd like to not display a hint at all, because the cursor is not over a real character. No doubt this is because EM_CHARFROMPOS is zero-based and returns a 0 for the 1st char, 1 for the and char, etc. And that's fine when the mouse is over a legitimate character in the TRichEdit... but when it's over empty space, the EM_CHARFROMPOS still returns a 0 and this is throwing me off. If only the EM_CHARFROMPOS would return a "-1" or something when the mouse is not hovering over a real character, then that would be perfect.
   Here is the code of my routine:

procedure TForm1.sRichEdit2MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  iCharIndex, lnth: Integer;
  Pt: TPoint;
  sHint: string;
begin
  sRichEdit2.hint := '';     // Clear out the old hint
  if Length(sRichEdit2.Text) <= 0 then EXIT;    // if nothing in TRichEdit, then just exit

  with TRichEdit(Sender) do
  begin
    Pt := Point(X, Y);

    // Get Character Index from word under the cursor
    iCharIndex := Perform(Messages.EM_CHARFROMPOS, 0, Integer(@Pt));

    if iCharIndex < 0 then EXIT;

    iCharIndex := iCharIndex + 1;
    lnth := Length(sRichEdit2.Text);
    if iCharIndex > lnth then EXIT;

    sHint:= IntToStr(iCharIndex);

    if TRichEdit(Sender).Hint <> sHint then
       TRichEdit(Sender).Hint := 'Index is '+ sHint;

    Application.ActivateHint(TRichEdit(Sender).ClientToScreen(Point(X,Y)));
  end;
end;

Open in new window



Any suggestions/thought please...?

Thanks!
   Shawn

P.S: I'm using Delphi 7.
shawn857Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

shawn857Author Commented:
I think I may have found part of the problem. Please see the attached screenshot. When I type only 3 characters into the RichEdit, it seems to place an automatic "space" right after the final character, as evidenced when I highlight all the text. And of course, EM_CHARFROMPOS counts this as a character and then the index count will be off. Any idea why TRichEdit does this?
   Maybe a "Trim" command on the contents of the RichEdit at the start of my routine might help? I'm going to try....

Thanks
    Shawn
spaceatend.PNG
jimyXCommented:
Hi Shawn,

As long as all the work is done through API's, am afraid, that is not possible.

You can read the MSDN for this particular limitation.

Remarks

If the location specified in the pt parameter is outside the client area of the control, the first character of the string closest to the point specified in pt is returned. You can use this method to determine which characters are located near a specific point within the control. You can then use this value to perform operations on the text at that location.

    Note   If the specified location in the pt parameter is located on the right side of the client area of the control, the last character of the string closest to the point specified in pt is returned.
jimyXCommented:
> it seems to place an automatic "space" right after the final character, as evidenced when I highlight all the text. And of course, EM_CHARFROMPOS counts this as a character and then the index count will be off. Any idea why TRichEdit does this?

The extra space at the end is actually the LF, when you have multiple lines.
It does not appear unless you select beyond the end of the current line. Even you can copy it to notepad.
As you know, if you have LF & CR then the length(RE.Text) will be the visible text length plus two for each line.
And that extra visible uncounted space, that appears when you have one line (no matter what length) it does nothing actually but it is extending the selection functionality to detect the LF, when present.
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

shawn857Author Commented:
I think I solved it Jimy... modified my routine to this:

procedure TForm1.sRichEdit2MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  iCharIndex: Integer;
  Pt: TPoint;
  sHint: string;
begin
  sRichEdit2.hint := '';     // Clear out the old hint
  lnth := Length(sRichEdit2.Text);
  if lnth <= 0 then EXIT;    // if nothing in TRichEdit, then just exit

  with TRichEdit(Sender) do
  begin
    Pt := Point(X, Y);

    // Get Character Index from word under the cursor
    iCharIndex := Perform(EM_CHARFROMPOS, 0, Integer(@Pt));

    if iCharIndex < 0 then EXIT;

    if iCharIndex >= lnth then
       iCharIndex := iCharIndex - 1;

    sHint:= IntToStr(iCharIndex);

    if TRichEdit(Sender).Hint <> sHint then
       TRichEdit(Sender).Hint := 'Index is '+sHint+ '. Char is '+sRichEdit2.Text[iCharIndex+1];

    Application.ActivateHint(TRichEdit(Sender).ClientToScreen(Point(X,Y)));
  end;
end;

Open in new window



That seems to work well. If I hover the mouse atsome empty white space at the far right of the TRichEdit, it displays a hint for the right-most character which I can live with... this is an inherent property of EM_CHARFROMPOS anyhow. Thanks for responding Jimy!

Cheers
   Shawn
jimyXCommented:
On the other hand, to avoid MS Component limitation, did you try some other components? Such as SynEdit?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
shawn857Author Commented:
I've never heard of it Jimy... I'll have to check it out. What's it all about, in general? Do you know of some screenshots of it, or sample Delphi projects that use it?

Thanks
    Shawn
jimyXCommented:
Mainly it's a syntax highlighter but it could easily replace MS RichEdit (Keep in mind it is not a clone of RichEdit, they are different).
It comes with demos you can check them out (download first).
Or check Google (see images), it will show you a lot of different uses it could fit.
shawn857Author Commented:
I will check out SynEdit, thanks for the suggestion Jimy!

Cheers
   Shawn
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.