【问题标题】:Form position on screen (FMX, Win32)屏幕上的表格位置(FMX,Win32)
【发布时间】:2018-12-11 03:38:52
【问题描述】:

我想知道我的表单在屏幕上的位置。我查看了位置属性(例如 this->Top、this->Left 等),但它们似乎不符合要求。我希望能够确定我的表单与屏幕顶部/底部以及屏幕左侧/右侧的距离。

我正在使用 C++ Builder 和 FMX 构建一个 Win32 应用程序。

谢谢,拉斯

更新 1:事实证明,我真正需要的是找到相对于整个桌面的坐标 (X,Y),而不仅仅是主显示器。桌面跨越多台显示器。

【问题讨论】:

    标签: firemonkey c++builder


    【解决方案1】:

    您的表单TopLeft 属性应该为您提供相对于活动桌面左上角的位置,但您可能还需要使用ClientToScreen/ScreenToClient。似乎很难在 FMX 中获得精确的偏移量。

    void __fastcall TForm1::MoveToTopLeft()
    {
        TPointF cli(0.0, 0.0);
        TPointF sp = ClientToScreen(cli);
    
        Left -= sp.x;
        Top = 0;
    }
    

    这个解决方案有些不对称...

    【讨论】:

    • 看看Screen.MonitorsScreen.MonitorCount,应该是Screen.Monitors[0].Width + Screen.Monitors[1].Width(无论如何在Delphi 中)
    • Screen->DesktopRect 使用DesktopRect确定整个虚拟桌面的坐标,包括系统中的所有显示器。 DesktopRect 以坐标表示,其中 (0,0) 是主监视器的左上角。主监视器是其 Primary 属性设置为 true 的监视器。
    • ...和Screen->DisplayCount 有助于循环浏览各个FMX 显示(C++ 中的Screen->Displays[idx])。在 VCL 中它被称为 Monitors
    • 我的 Screen->DesktopRect 描述是针对 VCL。 Screen->DesktopRect 的 FMX 描述是 获取虚拟屏幕矩形的像素参数。虚拟屏幕是指多显示系统。虚拟屏幕是构成桌面的所有显示器的边界矩形。
    • Ted 让我走上了正轨。我将使用Screen->DesktopWidthScreen->DesktopLeft 来确定我是在桌面的最右侧还是左侧(如果存在,则跨越多个显示器)。这与Screen->DesktopTop 一起会在我靠近任一边缘(左侧或右侧)或靠近整个桌面的顶部时通知我。
    【解决方案2】:

    根据 Ted 和 David 的输入,我整理了以下代码。如果表单的左边缘靠近桌面的左边缘(在 errX 像素内),它将弹出一条消息。如果表单客户区的顶部边缘靠近(在 errY 像素内)桌面的顶部边缘,它将弹出一条消息。不漂亮,但显示了这个想法。

    void __fastcall TForm1::Button4Click(TObject *Sender)
    {
    
    int dWidth = Screen->DesktopWidth;
    int dLeft = Screen->DesktopLeft;
    int dRight = dWidth + dRight;  // deskLeft is 0 if primary monitor is most left monitor
    int dTop = Screen->DesktopTop;
    int errX = 10;  // within 10 pixels is fine enough
    int errY = 40; // remember 30 or so pixels for caption bar
    TPointF cli(0.0, 0.0);
    TPointF sp = ClientToScreen(cli); //sp holds the coordinates for top left of form client area
    ShowMessage("X = " + FloatToStr(sp.x) + "\nY = " + FloatToStr(sp.y));  //show coordinates of top/left of form client area
    
    if (dLeft < 0) {  //negative value
     if ((abs(dLeft)-abs(sp.x)) < errX) {
      ShowMessage("Within " + IntToStr(errX) + " pixels of left edge."); // or further left of edge
     }
    }
    else {
     if ((dLeft + sp.x)< errX) {
      ShowMessage("Within " + IntToStr(errX) + " pixels of left edge."); // or further left of edge
     }
    }
    
    if (sp.x > 0) {  // no need to test the negative case
     if ((dRight-sp.x) < errX) {
      ShowMessage("Within " + IntToStr(errX) + " pixels of right edge."); // or further right of edge
     }
    }
    
    if ((dTop + sp.y)< errY) {
     ShowMessage("Within " + IntToStr(errY) + " pixels of top edge.");
    }
    
    }
    

    无论哪个监视器是主要的,此代码都有效。

    更新 1:当监视器未沿其顶部边缘对齐时,此代码会出现问题。在下图中,显示器 1 和 3 的顶部对齐。 2 没有。在此示例中,DesktopTop 返回 -876。所以看起来大卫对“监视器”的提示是要走的路——在 C++ 中它是“显示”。例如TRect myR = Screen-&gt;Displays[0].BoundsRect; 获取显示 0 的矩形,然后 int theTop = myR.top; 找到此特定显示的顶部。

    谢谢,拉斯

    【讨论】:

    • 如果你想在函数中运行它,那么需要TPointF sp = Form1-&gt;ClientToScreen(cli); 来获得正确的 ClientToScreen 范围。
    猜你喜欢
    • 1970-01-01
    • 2019-05-03
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多