Подтвердить что ты не робот

С# Получить контрольную позицию в форме

Есть ли способ получить позицию управления в форме, когда элемент управления может находиться внутри других элементов управления (например, панелей)?

Элементы управления Left и Top дают мне только позицию в нем родительского элемента управления, но что, если мой элемент управления находится внутри пяти вложенных панелей, и мне нужна его позиция в форме?

Быстрый пример:

Кнопка btnA расположена в координатах (10,10) внутри панели pnlB.
Панель pnlB расположена в координатах (15,15) внутри формы frmC.

Я хочу местоположение btnA на frmC, которое (25,25).

Могу ли я получить это местоположение?

4b9b3361

Ответ 1

Я обычно объединяю PointToScreen и PointToClient:

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

Ответ 2

Вы можете использовать метод управления PointToScreen, чтобы получить абсолютное положение относительно экрана.

Вы можете использовать метод Forms PointToScreen и с базовой математикой получить контрольную позицию.

Ответ 3

Вы могли бы пройти через родителей, отметив их положение в своем родителе, пока не прибудете в форму.

Изменить: что-то вроде (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;
}

Ответ 4

Я обычно делаю это так. Работает каждый раз..

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

Ответ 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;
}

Ответ 6

Как ни странно, PointToClient и PointToScreen не были идеальными для моей ситуации. Особенно потому, что я работаю с контрольными элементами, которые не связаны ни с какой формой. Я нашел решение sahin наиболее полезным, но вынул рекурсию и исключил завершение формы. Нижеприведенное решение работает для любого из моих элементов управления, видимых или нет, содержащихся в форме или нет, IContainered или нет. Спасибо Сахим.

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

Ответ 7

В моем тестировании решения Ганса Кестинга и Фредрика Мёрка дали тот же ответ. Но:

Я нашел интересное несоответствие в ответе, используя методы Раджа Мора и Ганса Кестинга, и подумал, что поделюсь. Спасибо, хотя и за их помощь; Я не могу поверить, что такой метод не встроен в структуру.

Обратите внимание, что Raj не записывал код, и поэтому моя реализация может отличаться от того, что он имел в виду.

Разница, которую я обнаружил, заключалась в том, что метод от Raj More часто был на два пиксела больше (как в X, так и Y), чем метод от Hans Kesting. Я еще не определил, почему это происходит. Я почти уверен, что это имеет какое-то отношение к тому факту, что, по-видимому, существует двухпиксельная граница вокруг содержимого формы Windows (например, внутри самой внешней формы). В моем тестировании, которое, конечно же, не было исчерпывающим, я только сталкивался с ним на элементах управления, которые были вложены. Однако не все вложенные элементы управления демонстрируют это. Например, у меня есть TextBox внутри GroupBox, который показывает несоответствие, но кнопка внутри того же GroupBox этого не делает. Я не могу объяснить, почему.

Обратите внимание, что, когда ответы эквивалентны, они рассматривают точку (0, 0) внутри границы содержимого, упомянутой выше. Поэтому я считаю, что я буду рассматривать решения Hans Kesting и Fredrik Mörk, но не думаю, что буду доверять решению, которое я реализовал в Raj More's.

Я также задавался вопросом, какой именно код Raj More написал бы, поскольку он дал идею, но не предоставил код. Я не полностью понял метод PointToScreen(), пока не прочитал этот пост: http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495

Вот мой метод тестирования. Обратите внимание, что "Метод 1", упомянутый в комментариях, несколько отличается от метода Ханса Кестинга.

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

Ответ 8

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

Ответ 9

Это то, что я сделал, работает как шарм

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