2009. május 21., csütörtök

How to detect a mouse movement over a word in a TRichEdit


Problem/Question/Abstract:

How to detect a mouse movement over a word in a TRichEdit

Answer:

Solve 1:

How can I detect when the mouse runs over a word or an expression in a TRichEdit?

You start by adding a handler to the TRichEdit's OnMouseMove event. In the handler you get to the character under the mouse with:

uses
  richedit; {for EM_EXLINEFROMCHAR}

var
  pt: TPoint;
  charindex, lineindex, charoffset: Integer;
begin
  pt := Point(X, Y);
  charindex := richedit.perform(Messages.EM_CHARFROMPOS, 0, integer(@pt));
  if charindex >= 0 then
  begin
    lineindex := richedit.perform(EM_EXLINEFROMCHAR, 0, charindex);
    charoffset := charindex - richedit.perform(EM_LINEINDEX, lineindex, 0);
  end;
end;

Lineindex and charoffset now allow you to get the line out of the richedit.Lines array and look at the characters value. Note that you have to use charoffset+1 as index into the string, e.g.:

S := richedit.lines[lineindex];
charundercursor := S[charoffset + 1];

If charundercursor is a letter (IsCharAlpha( charundercursor )) you could now walk backwards in S to find the start of the word and forward to find its end. Similar for an "expression" (whatever that may mean in your context).


Solve 2:

Using the source code above, how can I determine, whether the mouse is over a phrase like 'Inprise Delphi', which has the text attribute Bold and the colour Lime?

Well, you have to jump through some hoops, I'm afraid. The TRichEdit component has a method FindText that can be used to search for text, ignoring any text attributes. It would go something like this:

{additional vars required}
S: string;
foundPos, oldSelStart: Integer;

{after determining charindex as above}
S := 'Inprise Delphi'; {text to search for}
foundpos := richedit.FindText(S, charindex - Length(S) + 1, charindex + Length(S),
  [stWholeWord, stMatchCase]);
if foundpos > = 0 then
begin
  {found the text, check attributes}
  {for this we need to select the text}
  oldSelStart := richedit.SelStart;
  richedit.SelStart := foundPos;
  richedit.SelLength := Length(S);
  with richedit.SelAttributes do
    if ((ConsistentAttributes * [caBold, caColor]) = [caBold, caColor]) and
      (Color = clLime) and (fsBold in Style) then
      {we have a match!}
    else
      SelStart := oldSelStart;
end;


Solve 3:

How can I tell from a WM_MOUSEMOVE message that the mouse cursor is over a particular character or line of a TRichedit? I am simulating a very simplistic browser and want to know when the user is over a "hyperlink" which is really just a TRichedit with some of the text underlined. That way I can tell the cursor to change from crHand and back.

uses
  richedit;

var
  pt: TPoint;
  charindex, row, col: Integer;

{ ... }
GetCursorPos(pt);
pt := richedit.screentoclient(pt);
charindex := richedit1.perform(Messages.EM_CHARFROMPOS, 0, integer(@pt));
Row := richedit1.PerForm(EM_EXLINEFROMCHAR, 0, charindex);
Col := charindex - richedit1.Perform(EM_LINEINDEX, Row, 0);


Solve 4:

Looking for a way to find the character position the mouse is over during a TRichEdit.onMouseMove event.

var
  msg: TMessage;
  pt: TPoint;
  pos: integer; {offset into RichEdit.Text}

{ ... }
pt.x := X;
pt.y := Y;
msg.Result := SendMessage(RichEdit.handle, EM_CHarFromPos, 0, Integer(@pt));
pos := msg.ResultLo;
if RichEdit.Text[pos] = '?' then
  { ... }

Nincsenek megjegyzések:

Megjegyzés küldése