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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1478022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:55:54  来源:igfitidea点击:

C# Get a control's position on a form

c#winformscontrols

提问by Erlend D.

Is there any way to retrieve a control's position in a form, when the control may be inside other controls (like Panels)?

当控件可能位于其他控件(如面板)内时,有什么方法可以检索表单中控件的位置?

The control's Left and Top properties gives me only it's position within it's parent control, but what if my control is inside five nested panels, and I need it's position on the form?

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

Quick example:

快速示例:

The button btnA is located on coordinates (10,10) inside the panel pnlB.
The panel pnlB is located on coordinates (15,15) inside the form frmC.

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

I want btnA's location on frmC, which is (25,25).

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

Can I get this location?

我可以得到这个位置吗?

采纳答案by Fredrik M?rk

I usually combine PointToScreenand PointToClient:

我通常结合PointToScreenPointToClient

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

回答by Hans Ke?ing

You could walk up through the parents, noting their position within their parent, until you arrive at the Form.

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

Edit: Something like (untested):

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

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

回答by Raj More

You can use the controls PointToScreenmethod to get the absolute position with respect to the screen.

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

You can do the Forms PointToScreenmethod, and with basic math, get the control's position.

您可以使用 FormsPointToScreen方法,并通过基本数学运算,获取控件的位置。

回答by Tyler Collier

In my testing, both Hans Kesting's and Fredrik M?rk's solutions gave the same answer. But:

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

I found an interesting discrepancy in the answer using the methods of Raj More and Hans Kesting, and thought I'd share. Thanks to both though for their help; I can't believe such a method is not built into the framework.

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

Please note that Raj didn't write code and therefore my implementation could be different than he meant.

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

The difference I found was that the method from Raj More would often be two pixels greater (in both X and Y) than the method from Hans Kesting. I have not yet determined why this occurs. I'm pretty sure it has something to do with the fact that there seems to be a two-pixel border around the contentsof a Windows form (as in, inside the form's outermost borders). In my testing, which was certainly not exhaustive to any extent, I've only come across it on controls that were nested. However, not all nested controls exhibit it. For example, I have a TextBox inside a GroupBox which exhibits the discrepancy, but a Button inside the same GroupBox does not. I cannot explain why.

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

Note that when the answers are equivalent, they consider the point (0, 0) to be insidethe content border I mentioned above. Therefore I believe I'll consider the solutions from Hans Kesting and Fredrik M?rk to be correct but don't think I'll trust the solution I've implemented of Raj More's.

请注意,当答案相同时,他们认为点 (0, 0)位于我上面提到的内容边界。因此,我相信我会认为 Hans Kesting 和 Fredrik M?rk 的解决方案是正确的,但不认为我会相信我已经实施的 Raj More 的解决方案。

I also wondered exactly what code Raj More would have written, since he gave an idea but didn't provide code. I didn't fully understand the PointToScreen() method until I read this post: http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495

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

Here's my method for testing. Note that 'Method 1' mentioned in the comments is slightly different than Hans Kesting's.

这是我的测试方法。请注意,评论中提到的“方法 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;
}

回答by sahin

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

回答by BoeroBoy

Oddly enough, PointToClient and PointToScreen weren't ideal for my situation. Particularly because I'm working with offscreen controls that aren't associated with any form. I found sahin's solution the most helpful, but took out recursion and eliminated the Form termination. The solution below works for any of my controls visible or not, Form-contained or not, IContainered or not. Thanks Sahim.

奇怪的是,PointToClient 和 PointToScreen 并不适合我的情况。特别是因为我正在使用与任何表单无关的屏幕外控件。我发现 sahin 的解决方案最有帮助,但取消了递归并消除了 Form 终止。下面的解决方案适用于我的任何控件是否可见,是否包含表单,是否包含 IContainer。谢谢萨希姆。

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

回答by Plater

Supergeek, your non recursive function did not producte the correct result, but mine does. I believe yours does one too many additions.

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

回答by noisyass2

I usually do it like this.. Works every time..

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

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

回答by shiroxx

This is what i've done works like a charm

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

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