7

I want to know the position of the cursor on a TCustomControl. How does one go about finding the coordinates?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Little Helper
  • 2,419
  • 9
  • 37
  • 67

3 Answers3

17

GetCursorPos can be helpful if you can't handle a mouse event:

function GetCursorPosForControl(AControl: TWinControl): TPoint;
var 
  P: TPoint; 
begin
  Windows.GetCursorPos(P);
  Windows.ScreenToClient(AControl.Handle, P );
  result := P;
end;
splash
  • 13,037
  • 1
  • 44
  • 67
  • 8
    FWIW, GetCursorPos doesn't work correctly on 64 bit XP/Vista when the TPoint instance is located at a memory address >2MB. MS fixed this in Windows 7. Myself, I always use GetCursorInfo to sidestep the bug. – David Heffernan Jul 11 '11 at 12:40
7

You can use MouseMove event:

procedure TCustomControl.MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Label1.Caption := IntToStr(x) + ' ' + IntToStr(y);       
end;
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
TheHorse
  • 2,787
  • 1
  • 23
  • 32
  • I am using this: procedure WMMouseMove(var message: TWMMouseMove); message WM_MOUSEMOVE; – Little Helper Jul 11 '11 at 09:08
  • 1
    @Robrok, why handle `WM_MOUSEMOVE` directly when you can assign an `OnMouseMove` Delphi-style event handler and be done with it? If you insist on using `WM_MOUSEMOVE`, the coordinates are in `msg.Lparam`, according to [the documentation](http://msdn.microsoft.com/en-us/library/ms645616(v=vs.85).aspx) – Cosmin Prund Jul 11 '11 at 09:11
  • 1
    +1, and I took the liberty to remove the `ShowMessage` and replace it with a `Label1.Caption := X Y`, because setting the Caption is non-modal, you can move the mouse over the control and see it update. `ShowMessage` is modal, as soon as the mouse is over the control the message pops and nothing else happens until you click "Ok" – Cosmin Prund Jul 11 '11 at 09:15
  • Sorry, i didnt see that OnMouseMove is defined in TCustomControl. :) – Little Helper Jul 11 '11 at 09:19
  • 2
    @Robrok, if you're *writing* the control, then you shouldn't use `OnMouseMove`. That's for *users* of the control. *Writers* of controls should override the `MouseMove` method, as demonstrated here. – Rob Kennedy Jul 11 '11 at 12:59
5

If you want the cursor position when they click on the control, then use Mouse.CursorPos to get the mouse position, and Control.ScreenToClient to convert this to the position relative to the Control.

procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  pt: TPoint;
begin
  pt := Mouse.CursorPos;
  pt := Memo1.ScreenToClient(pt);
  Memo1.Lines.Add(Format('x=%d, y=%d', [pt.X, pt.y]));
end;

EDIT:

As various people have pointed out, this is pointless on a mouse down event. However as TCustomControl.OnMouseDown is protected, it may not always be readily available on third-party controls - mind you I would probably not use a control with such a flaw.

A better example might be an OnDblClick event, where no co-ordinate information is given:

procedure TForm1.DodgyControl1DblClick(Sender: TObject);
var
  pt: TPoint;
begin
  pt := Mouse.CursorPos;
  pt := DodgyControl1.ScreenToClient(pt);
  Memo1.Lines.Add(Format('x=%d, y=%d', [pt.X, pt.y]));
end;
Gerry Coll
  • 5,867
  • 1
  • 27
  • 36
  • 4
    You get the X and Y coordinates as parameters to the event handler, relative to the control. Your code to grab the coordinates from `Mouse.CursorPos` and convert them to "control coordinates" is redundant! – Cosmin Prund Jul 11 '11 at 09:18
  • Yes. It is intended as demo code, rather than as a recommendation. – Gerry Coll Jul 11 '11 at 09:38
  • You say: `"If you want the cursor position when they click on the control, then use Mouse.CursorPos to get the mouse position, and Control.ScreenToClient to convert this to the position relative to the Control."`: I disagree. Use the **received** X and Y coordinates if you need to know where the user clicked. – Cosmin Prund Jul 11 '11 at 09:42
  • @Cosmin - I meant for a control that for whatever reason didn't promote OnMouseDown from protected to public. The code here could be used from OnClick or OnDblClick event. I just choose a bad event handler to call it from. From memory, the OnMouse* events weren't in early versions (maybe introduced in D5 or 6 - they are definitely in D6) – Gerry Coll Jul 11 '11 at 12:22
  • FWIW, Mouse.CursorPos is subject to the same bug that I describe in @splash's answer. – David Heffernan Jul 11 '11 at 12:41
  • methinks - **excessive surplus redundancy**, coordinates already ready to use – Premature Optimization Jul 11 '11 at 16:14
  • @Gerry This makes it a poor demo then. A good demo would suggest the use of the X and Y parameters. – David Heffernan Jul 11 '11 at 16:47