C# получить позицию элемента управления в форме
есть ли способ получить положение элемента управления в форме, когда элемент управления может находиться внутри других элементов управления (например, панелей)?
левые и верхние свойства элемента управления дают мне только его позицию в родительском элементе управления, но что делать, если мой элемент управления находится внутри пяти вложенных панелей, и мне нужна его позиция в форме?
пример:
кнопка btnA расположена по координатам (10,10) внутри панели pnlB.
Панель pnlB расположена на координаты (15,15) внутри формы frmC.
Я хочу, чтобы местоположение btnA на frmC, которое составляет (25,25).
могу ли я получить это место?
9 ответов:
Я обычно совмещают
PointToScreenиPointToClient:Point locationOnForm = control.FindForm().PointToClient( control.Parent.PointToScreen(control.Location));
Вы можете использовать элементы управления
PointToScreenметод, чтобы получить абсолютное положение относительно экрана.Вы можете сделать формы
PointToScreenметод, и с основной математикой, получить положение элемента управления.
вы можете пройти через родителей, отмечая их положение внутри своего родителя, пока не дойдете до формы.
правка: что-то вроде (непроверенных):
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; }
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; }
Как ни странно, PointToClient и PointToScreen не были идеальными для моей ситуации. Особенно потому, что я работаю с закадровыми элементами управления, которые не связаны с какой-либо формой. Я нашел решение Сахина наиболее полезным, но вынул рекурсию и устранил завершение формы. Решение ниже работает для любого из моих элементов управления, видимых или нет, содержащихся в форме или нет, 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; }
в моем тестировании решения Ганса Кестинга и Фредрика Мерка дали один и тот же ответ. Но:
Я нашел интересное несоответствие в ответе, используя методы Раджа Мора и Ганса Кестинга, и подумал, что поделюсь. Спасибо хоть за помощь; я не могу поверить, что такой метод не встроен в платформу.
обратите внимание, что Радж не писал код, и поэтому моя реализация может отличаться от того, что он имел в виду.
разница I оказалось, что метод из Raj More часто будет на два пикселя больше (как в X, так и в Y), чем метод из Hans Kesting. Я еще не определил почему это происходит. Я почти уверен, что это как-то связано с тем, что вокруг содержание формы Windows (например, внутри внешних границ формы). В моем тестировании, которое, безусловно, не было исчерпывающим в какой-либо степени, я столкнулся с ним только на вложенных элементах управления. Однако, не все вложенные элементы управления показывают его. Например, у меня есть текстовое поле внутри группового поля, которое показывает несоответствие, но кнопка внутри того же группового поля не делает. Я не могу объяснить, почему.
обратите внимание, что когда ответы эквивалентны, они считают точку (0, 0)внутри граница содержания, о которой я упоминал выше. Поэтому я считаю, что я буду считать решения от Ханса Кестинга и Фредрика Мерка правильными, но не думаю, что я буду доверять решению, которое у меня есть реализовано Раджа Мора.
мне также было интересно, какой именно код написал бы Радж Мор, так как он дал идею, но не предоставил код. Я не полностью понял метод PointToScreen (), пока не прочитал этот пост: http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495
вот мой метод для тестирования. Обратите внимание, что "метод 1", упомянутый в комментариях, немного отличается от Hans Кестинг это.
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); p.X += ctrl.Location.X; p.Y += 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); }
Comments