C#获取控件在表单上的位置

时间:2009-09-25 15:31:52

标签: c# winforms controls

当控件可能位于其他控件(如Panel)中时,有没有办法检索控件在窗体中的位置?

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

快速举例:

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

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

我能获得这个位置吗?

9 个答案:

答案 0 :(得分:84)

我通常会合并PointToScreenPointToClient

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

答案 1 :(得分:11)

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

你可以使用Forms PointToScreen方法,并使用基本数学,获得控件的位置。

答案 2 :(得分:7)

我通常这样做..每次都有效..

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

答案 3 :(得分: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;
}

答案 4 :(得分:5)

Supergeek,你的非递归函数没有产生正确的结果,但我的确如此。我相信你的做法太多了。

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

答案 5 :(得分:3)

奇怪的是,PointToClient和PointToScreen并不适合我的情况。特别是因为我正在使用与任何表单无关的屏幕外控件。我发现sahin的解决方案最有帮助,但是取出了递归并取消了Form终止。下面的解决方案适用于我的任何可见或不可用的控件,包含或不包含,IContainered与否。谢谢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;
}

答案 6 :(得分: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的解决方案。

我还想知道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;
}

答案 7 :(得分: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;
    }
}

答案 8 :(得分: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);
        }