如何获取控件相对于其所在窗体的位置?

10
我正在寻找一种方法,可以获取控件相对于其所在窗体的位置,而不是相对于窗体的客户区域左上角的位置。
当然,我可以将所有内容都转换为屏幕坐标,但我想知道是否有更直接的方法来实现这个目的。

你所说的“控件位置”确切指的是光标位置吗? - uday
@uDaY 我的意思是:以屏幕坐标为准。如果窗体在100,100处,控件在150,350处,我想要得到50,250。 - ispiro
小心:https://dev59.com/m1_Va4cB1Zd3GeqPRDbA - Hans Passant
5个回答

14

你需要将其转换为屏幕坐标,然后进行一些数学计算。

Point controlLoc = form.PointToScreen(myControl.Location);
的位置已经是屏幕坐标。

现在:

Point relativeLoc = new Point(controlLoc.X - form.Location.X, controlLoc.Y - form.Location.Y);

这将给出相对于表单左上角的位置,而不是相对于表单客户区域的位置。


谢谢您的回答,但正如我在问题中所写的那样,我正在寻找比检查屏幕坐标更直接的方法。 - ispiro
1
@ispiro:没有更直接的内置方法。您可以轻松地将该逻辑封装到一个小函数中,以便调用。或者,在首次显示表单时,您可以调用 form.PointToScreen(new Point(0, 0)),保存结果,然后在需要获取窗口相对坐标时,只需将 X 和 Y 值添加到控件的 Location 中即可。 - Jim Mischel
关于我上一条评论。我的意思是你需要调用PointToScreen方法来获取窗体客户区域的位置,并从Location的X和Y值中减去偏移量。对此我感到抱歉。 - Jim Mischel

6
我认为这将回答您的问题。请注意,“this”是指表格。
Rectangle screenCoordinates = control.Parent.ClientToScreen(control.ClientRectangle);
Rectangle formCoordinates = this.ScreenToClient(screenCoordinates);

谢谢您的回答,但正如我在问题中所写的那样,我正在寻找比检查屏幕坐标更直接的方法。 - ispiro

3

看起来答案是没有直接的方法来做到这一点。

(正如我在问题中所述,我正在寻找一种不使用屏幕坐标的方法。)


1

如果您的控件位于许多其他设置为自动调整大小的控件内部,则上述任何答案都无法帮助您,即:

Form -> FlowLayoutPanel -> Panel -> Panel -> Control

所以我已经用不同的逻辑编写了自己的代码,但是我不知道如果父控件之间使用了一些对接,结果会是什么样子。我猜测在这种情况下需要涉及边距和填充。

    public static Point RelativeToForm(this Control control)
    {

        Form form = control.FindForm();
        if (form is null)
            return new Point(0, 0);

        Control parent = control.Parent;

        Point offset = control.Location;            

        while (parent != null)
        {
            offset.X += parent.Left;
            offset.Y += parent.Top;                
            parent = parent.Parent;
        }

        offset.X -= form.Left;
        offset.Y -= form.Top;

        return offset;

    }

1
所选答案在问题的具体情况下从技术上讲是正确的:.NET框架中不存在这样的属性。但是,如果您想要这样的属性,这里有一个控件扩展可以解决问题。是的,它使用屏幕坐标,但考虑到帖子标题的一般性质,我相信一些用户可能会发现这很有用。顺便说一句,我花了几个小时尝试通过循环遍历所有控件父级来完成此操作,但我无法使两种方法协调一致。这可能是由于Hans Passant对OP关于Aero如何欺骗窗口大小的评论所致。
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Cambia
{
    public static class ControlExtensions
    {
        public static Point FormRelativeLocation(this Control control, Form form = null)
        {
            if (form == null)
            {
                form = control.FindForm();
                if (form == null)
                {
                    throw new Exception("Form not found.");
                }
            }

            Point cScreen = control.PointToScreen(control.Location);
            Point fScreen = form.Location;
            Point cFormRel = new Point(cScreen.X - fScreen.X, cScreen.Y - fScreen.Y);

            return cFormRel;

        }

    }
}

1
这是一个很好的解决方案。虽然我相信你想返回 cFormRel - Don Shrout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接