【问题标题】:Delphi How to get cursor position on a control?Delphi 如何获取控件上的光标位置?
【发布时间】:2011-07-11 08:56:18
【问题描述】:

我想知道光标在 TCustomControl 上的位置。如何找到坐标?

【问题讨论】:

    标签: delphi delphi-7 mouse-cursor


    【解决方案1】:

    如果您无法处理鼠标事件,GetCursorPos 会很有帮助:

    function GetCursorPosForControl(AControl: TWinControl): TPoint;
    var 
      P: TPoint; 
    begin
      Windows.GetCursorPos(P);
      Windows.ScreenToClient(AControl.Handle, P );
      result := P;
    end;
    

    【讨论】:

    • FWIW,当 TPoint 实例位于 >2MB 的内存地址时,GetCursorPos 在 64 位 XP/Vista 上无法正常工作。 MS 在 Windows 7 中修复了这个问题。我自己,我总是使用 GetCursorInfo 来回避这个错误。
    【解决方案2】:

    你可以使用 MouseMove 事件:

    procedure TCustomControl.MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
      Label1.Caption := IntToStr(x) + ' ' + IntToStr(y);       
    end;
    

    【讨论】:

    • 我正在使用这个:procedure WMMouseMove(var message: TWMMouseMove);消息 WM_MOUSEMOVE;
    • @Robrok,当您可以分配OnMouseMove Delphi 风格的事件处理程序并完成它时,为什么要直接处理WM_MOUSEMOVE?如果坚持使用WM_MOUSEMOVE,坐标在msg.Lparam,根据the documentation
    • +1,我冒昧的把ShowMessage去掉,换成Label1.Caption := X Y,因为设置Caption是非模态的,可以把鼠标移到控件上看看它更新。 ShowMessage 是模态的,只要鼠标悬停在控件上,消息就会弹出,并且在您单击“确定”之前不会发生任何其他事情
    • 抱歉,我没有看到 OnMouseMove 是在 TCustomControl 中定义的。 :)
    • @Robrok,如果你正在编写控件,那么你不应该使用OnMouseMove。这适用于控件的用户。控件的编写者应覆盖MouseMove 方法,如此处所示。
    【解决方案3】:

    如果您想要鼠标点击控件时的光标位置,则使用Mouse.CursorPos 获取鼠标位置,并使用Control.ScreenToClient 将其转换为相对于控件的位置。

    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;
    

    编辑:

    正如许多人所指出的,这对鼠标按下事件毫无意义。然而,由于 TCustomControl.OnMouseDown 受到保护,它可能并不总是在第三方控件上随时可用 - 请注意,我可能不会使用具有此类缺陷的控件。

    一个更好的例子可能是 OnDblClick 事件,它没有给出坐标信息:

    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;
    

    【讨论】:

    • 您获得 X 和 Y 坐标作为事件处理程序的参数,相对于控件。您从Mouse.CursorPos 获取坐标并将其转换为“控制坐标”的代码是多余的!
    • 是的。它旨在作为演示代码,而不是作为推荐。
    • 你说:"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.":我不同意。如果您需要知道用户点击的位置,请使用 received X 和 Y 坐标。
    • @Cosmin - 我的意思是一个控件,无论出于何种原因,它都没有将 OnMouseDown 从受保护状态提升为公开状态。此处的代码可用于 OnClick 或 OnDblClick 事件。我只是选择一个错误的事件处理程序来调用它。根据记忆,OnMouse* 事件不在早期版本中(可能在 D5 或 6 中引入 - 它们肯定在 D6 中)
    • FWIW,Mouse.CursorPos 受到我在@splash 的回答中描述的相同错误的影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 2023-02-12
    • 1970-01-01
    相关资源
    最近更新 更多