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

当控件可能位于其他控件(如面板)中时,是否有任何方法可以检索控件在窗体中的位置?

控件的Left和Top属性只给出了它在父控件中的位置,但是如果我的控件在五个嵌套面板中,我需要它在表单上的位置呢?

快速示例:

buttonbtnA位于面板pnlB内的坐标(10,10)上。
面板pnlB位于frmCforms的坐标(15,15)上。

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

我可以得到这个位置吗?

我通常结合PointToScreenPointToClient

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

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

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

你可以走过父母,注意他们在父母的位置,直到你到达表格。

编辑:像(未经testing)的东西:

 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; } 

我通常这样做..每次工作..

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

Supergeek,你的非recursion函数没有产生正确的结果,但我的。 我相信你有太多的补充。

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

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

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

我用Raj More和Hans Kesting的方法在答案中find了一个有趣的差异,并认为我会分享。 感谢这两个虽然他们的帮助; 我不能相信这样的方法不是内置于框架。

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

我发现的差异是来自Raj More的方法通常比Hans Kesting的方法大两个像素(在X和Y中)。 我还没有确定为什么会发生这种情况。 我敢肯定,它与Windows窗体的内容似乎有两个像素的边界(如在窗体的最外边框内)是有关系的。 在我的testing中,这个testing肯定不是全面的,我只是在嵌套的控件上遇到过。 但是,并不是所有的嵌套控件都显示它。 例如,我在一个GroupBox里面有一个文本框,它显示了这个差异,但是同一个GroupBox里面的Button没有。 我无法解释为什么。

请注意,当答案是相同的,他们认为点(0,0)是我上面提到的内容边界 。 因此,我相信我会考虑Hans Kesting和FredrikMörk的解决scheme是正确的,但不要相信我已经实施了Raj More的解决scheme。

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

这是我的testing方法。 请注意,评论中提到的“方法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; } 
 private Point FindLocation(Control ctrl) { if (ctrl.Parent is Form) return ctrl.Location; else { Point p = FindLocation(ctrl.Parent); pX += ctrl.Location.X; pY += ctrl.Location.Y; return p; } } 

这就是我所做的就像一个魅力

  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); }