如何将屏幕坐标转换为具有嵌入式形式和多显示器 FMX 的控件坐标 Windows

How to convert screen coordinates to control coordinates with embedded form and multiple displays FMX Windows

我需要知道 OnItemClickEx 事件中的鼠标位置以及相对于 ListView 控件的坐标。在多显示器系统中,它适用于在主显示器上显示的应用程序,但在应用程序显示在辅助或第三显示器上时不起作用。

获取鼠标位置的代码如下:

...
var point : TPointF;
...
point := Screen.MousePos;
point := self.ScreenToClient(point): //we obtain wrong local coordinates for the secondary and third monitor with or without this line 
point := ListView.AbsoluteToLocal(point);

了解鼠标光标相对于控件(在本用例中为 TListView)的坐标的正确方法是什么?

更新

this 示例中,您可以看到它在第一个表单中工作正常,但在嵌入式表单中它提供了错误的坐标。在10.2和10.3中测试,结果相同

以下代码与 Delphi 10.4.1 完美配合:

procedure TForm1.ListView1ItemClickEx(
    const Sender        : TObject;
    ItemIndex           : Integer;
    const LocalClickPos : TPointF;
    const ItemObject    : TListItemDrawable);
var
    PtScreen   : TPointF;
    PtForm     : TPointF;
    PtListView : TPointF;
begin
    PtScreen   := Screen.MousePos;
    PtForm     := ScreenToClient(PtScreen);
    PtListView := ListView1.AbsoluteToLocal(PtForm);

    Memo1.Lines.Add('ListView1ItemClickEx ' +
                    PtListView.X.ToString + ', ' + PtListView.Y.ToString);
    Memo1.GoToTextEnd;
end;

procedure TForm1.ListView1MouseMove(
    Sender : TObject;
    Shift  : TShiftState;
    X, Y   : Single);
begin
    Memo1.Lines.Add('ListViewMouseMove  ' +
                    X.ToString + ', ' + Y.ToString);
    Memo1.GoToTextEnd;
end;

此代码将在鼠标光标在 TListView 内移动时在备忘录中显示鼠标的坐标,并显示从 OnItemClickEx 事件计算的坐标。两者相同,在主显示器或辅助显示器上。

也许您使用的是旧 Delphi 版本,其中存在错误。我不知道。或者错误在您的代码中的其他地方。

如果您从 ListView OnMouseMove 事件处理程序捕获鼠标位置并将其保存在表单的变量中,以便从 OnItemClickEx 事件处理程序中随时可用,您的问题将得到解决:

private
    FMouseX : Single;
    FMouseY : Single;


procedure TForm1.ListView1MouseMove(
    Sender : TObject;
    Shift  : TShiftState;
    X, Y   : Single);
begin
    FMouseX := X;
    FMouseY := Y;
end;

procedure TForm1.ListView1ItemClickEx(
    const Sender        : TObject;
    ItemIndex           : Integer;
    const LocalClickPos : TPointF;
    const ItemObject    : TListItemDrawable);
begin
    Memo1.Lines.Add('ListView1ItemClickEx ' +
                    FMouseX.ToString + ', ' + FMouseY.Y.ToString);
    Memo1.GoToTextEnd;
end;

最后,经过一些研究和测试,我找到了窍门:

...
var point : TPointF;
...
  point := Screen.MousePos;
  point := Application.MainForm.ScreenToClient(point); // The calculation should be with the MainForm, not the embedded!!!
  point := ListView.AbsoluteToLocal(point);