I want to know the position of the cursor on a TCustomControl. How does one go about finding the coordinates?
Delphi How to get cursor position on a control?
Asked Answered
You can use MouseMove event:
procedure TCustomControl.MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Label1.Caption := IntToStr(x) + ' ' + IntToStr(y);
end;
I am using this: procedure WMMouseMove(var message: TWMMouseMove); message WM_MOUSEMOVE; –
Dashtikavir
@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 –
Murex +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" –
Murex Sorry, i didnt see that OnMouseMove is defined in TCustomControl. :) –
Dashtikavir
@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. –
Theine 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;
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. –
Rebak
You can use MouseMove event:
procedure TCustomControl.MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Label1.Caption := IntToStr(x) + ' ' + IntToStr(y);
end;
I am using this: procedure WMMouseMove(var message: TWMMouseMove); message WM_MOUSEMOVE; –
Dashtikavir
@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 –
Murex +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" –
Murex Sorry, i didnt see that OnMouseMove is defined in TCustomControl. :) –
Dashtikavir
@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. –
Theine 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;
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! –
Murex Yes. It is intended as demo code, rather than as a recommendation. –
Faculty
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. –
Murex @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) –
Faculty
FWIW, Mouse.CursorPos is subject to the same bug that I describe in @splash's answer. –
Rebak
methinks - excessive surplus redundancy, coordinates already ready to use –
Kindling
@Gerry This makes it a poor demo then. A good demo would suggest the use of the X and Y parameters. –
Rebak
© 2022 - 2024 — McMap. All rights reserved.