C#获取控件在窗体上的位置


71

当控件可能位于其他控件(如“面板”)内部时,是否有任何方法可以检索表单中的控件位置?

控件的Left和Top属性只给我它在父控件中的位置,但是如果我的控件在五个嵌套面板中,并且我需要它在窗体上的位置怎么办?

快速示例:

按钮btnA位于面板pnlB内部的坐标(10,10)上。
面板pnlB位于表格frmC内的坐标(15,15)上。

我想要btnA在frmC上的位置是(25,25)。

我可以得到这个位置吗?

Answers:


97

我通常结合PointToScreenPointToClient

Point locationOnForm = control.FindForm().PointToClient(
    control.Parent.PointToScreen(control.Location));

9
这是REAL ABSOULUTE POSITION stackoverflow.com/questions/4998076/...
PUG

4
control.PointToScreen(Point.Empty);有何不同?
strongriley

1
@strongriley不知道(从来没有尝试过,现在还没有可用的dev env),但是我看不到文档中提到的行为,如果这样的话,也不能保证它会在将来的框架版本中起作用。
FredrikMörk'12

5
@strongrileycontrol.PointToScreen(Point.Empty)给出相对于屏幕的位置,而答案则给出相对于顶层表格的位置。
nawfal 2012年

嘿,您在此方面为我提供了很多帮助:)它使设计的弹出窗口位于程序显示中心,而不是位于所有屏幕的中心!
kokbira 2012年

11

您可以使用控件PointToScreen方法来获取相对于屏幕的绝对位置。

您可以执行FormsPointToScreen方法,并使用基本数学方法获得控件的位置。


除非您考虑标题栏的高度和表单边框的宽度,否则这将无法完全正确地工作。
MusiGenesis

这对获得控件的绝对位置有何帮助?您必须将Point对象传递给PointToScreen(),在这种情况下这没有意义。
蒂姆(Tim)

@Tim,在这种情况下,您必须传递System.Drawing.Point.Empty:var absolutePosition = control.PointToScreen(System.Drawing.Point.Empty);
Umar T.

10

我通常是这样做的。

var loc = ctrl.PointToScreen(Point.Empty);

6

您可以遍历父母,注意他们在父母中的位置,直到您到达表格。

编辑:类似(未经测试):

public Point GetPositionInForm(Control ctrl)
{
   Point p = ctrl.Location;
   Control parent = ctrl.Parent;
   while (! (parent is Form))
   {
      p.Offset(parent.Location.X, parent.Location.Y);
      parent = parent.Parent;
   }
   return p;
}

是的,我想到了这一点,但是这似乎是不切实际的方式,所以我希望有另一种方式。如果没有其他建议,那就是我会做的。
Erlend D.

这是使用简单递归函数的方法。
MusiGenesis

5

超级极客,您的非递归函数无法产生正确的结果,但是我的却可以。我相信您的添加太多了。

private Point LocationOnClient(Control c)
{
   Point retval = new Point(0, 0);
   for (; c.Parent != null; c = c.Parent)
   { retval.Offset(c.Location); }
   return retval;
}

3

奇怪的是,PointToClient和PointToScreen在我的情况下并不理想。特别是因为我正在使用与任何形式都不相关的屏幕外控件。我发现sahin的解决方案最有用,但是进行了递归并消除了Form终止。以下解决方案适用于我的任何控件(无论是否可见),是否包含表单,是否包含IContainer。谢谢Sahim。

private static Point FindLocation(Control ctrl)
{
    Point p;
    for (p = ctrl.Location; ctrl.Parent != null; ctrl = ctrl.Parent)
        p.Offset(ctrl.Parent.Location);
    return p;
}

1

在我的测试中,Hans Kesting和FredrikMörk的解决方案给出了相同的答案。但:

我使用Raj More和Hans Kesting的方法在答案中发现了一个有趣的差异,并认为我会分享。感谢双方的帮助;我不敢相信这种方法没有内置在框架中。

请注意,Raj没有编写代码,因此我的实现可能与他的意思不同。

我发现的区别是,Raj More的方法通常比Hans Kesting的方法大两个像素(在X和Y方向上)。我尚未确定为什么会发生这种情况。我非常确定,这与Windows窗体的内容周围似乎有两个像素的边框有关(例如,在窗体的最外面的边框内部)。在我的测试中,这当然在任何程度上都不是详尽无遗的,我只是在嵌套的控件上碰到过它。但是,并非所有嵌套控件都可以显示它。例如,我在GroupBox内有一个TextBox表现出差异,但是在同一GroupBox内没有Button。我无法解释原因。

请注意,当答案相等时,它们会认为点(0,0)我上面提到的内容边界之。因此,我相信我会认为Hans Kesting和FredrikMörk的解决方案是正确的,但我认为我不会相信我为Raj More's实现的解决方案。

我还想知道Raj More会写什么代码,因为他给出了一个主意,但没有提供代码。在阅读这篇文章之前,我还没有完全理解PointToScreen()方法:http : //social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495

这是我的测试方法。请注意,注释中提到的“方法1”与Hans Kesting的方法略有不同。

private Point GetLocationRelativeToForm(Control c)
{
  // Method 1: walk up the control tree
  Point controlLocationRelativeToForm1 = new Point();
  Control currentControl = c;
  while (currentControl.Parent != null)
  {
    controlLocationRelativeToForm1.Offset(currentControl.Left, currentControl.Top);
    currentControl = currentControl.Parent;
  }

  // Method 2: determine absolute position on screen of control and form, and calculate difference
  Point controlScreenPoint = c.PointToScreen(Point.Empty);
  Point formScreenPoint = PointToScreen(Point.Empty);
  Point controlLocationRelativeToForm2 = controlScreenPoint - new Size(formScreenPoint);

  // Method 3: combine PointToScreen() and PointToClient()
  Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));

  // Theoretically they should be the same
  Debug.Assert(controlLocationRelativeToForm1 == controlLocationRelativeToForm2);
  Debug.Assert(locationOnForm == controlLocationRelativeToForm1);
  Debug.Assert(locationOnForm == controlLocationRelativeToForm2);

  return controlLocationRelativeToForm1;
}

1
private Point FindLocation(Control ctrl)
{
    if (ctrl.Parent is Form)
        return ctrl.Location;
    else
    {
        Point p = FindLocation(ctrl.Parent);
        p.X += ctrl.Location.X;
        p.Y += ctrl.Location.Y;
        return p;
    }
}

0

这就是我做的像魅力一样的作品

            private static int _x=0, _y=0;
        private static Point _point;
        public static Point LocationInForm(Control c)
        {
            if (c.Parent == null) 
            {
                _x += c.Location.X;
                _y += c.Location.Y;
                _point = new Point(_x, _y);
                _x = 0; _y = 0;
                return _point;
            }
            else if ((c.Parent is System.Windows.Forms.Form))
            {
                _point = new Point(_x, _y);
                _x = 0; _y = 0;
                return _point;
            }
            else 
            {
                _x += c.Location.X;
                _y += c.Location.Y;
                LocationInForm(c.Parent);
            }
            return new Point(1,1);
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.