2009-09-25 39 views
53

Có cách nào để lấy lại vị trí của điều khiển trong biểu mẫu hay không, khi điều khiển có thể nằm trong các điều khiển khác (như Bảng điều khiển)?C# Có được vị trí của điều khiển trên mẫu

Thuộc tính Trái và Trên của điều khiển chỉ cho tôi vị trí của nó trong điều khiển gốc, nhưng điều gì sẽ xảy ra nếu điều khiển của tôi nằm trong năm bảng lồng nhau và tôi cần vị trí trên biểu mẫu?

nhanh Ví dụ:

Nút btnA nằm trên tọa độ (10,10) bên trong bảng điều khiển pnlB.
Bảng điều khiển pnlB nằm trên tọa độ (15,15) bên trong biểu mẫu frmC.

Tôi muốn vị trí của btnA trên frmC, là (25,25).

Tôi có thể lấy vị trí này không?

Trả lời

77

tôi thường kết hợp PointToScreenPointToClient:

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

Đây là 'REAL ABSOULUTE POSITION' http://stackoverflow.com/questions/4998076/getting-the-location-of-a-control-relative-to-the-entire-screen – PUG

+3

Điều này khác với 'điều khiển như thế nào .PointToScreen (Point.Empty); '? – strongriley

+1

@strongriley Không có ý tưởng (không bao giờ thử nó và không có env dev có sẵn ngay bây giờ), nhưng tôi không thể nhìn thấy hành vi đó được đề cập trong tài liệu, và nếu như vậy không có đảm bảo rằng nó sẽ hoạt động trong phiên bản khuôn khổ trong tương lai. –

6

Bạn có thể đi bộ qua cha mẹ, ghi nhận vị trí của họ trong cha mẹ cho đến khi bạn đến Biểu mẫu.

Chỉnh sửa: Giống như (chưa được kiểm tra):

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

arrggg ... đánh tôi với nó :) – armannvg

+0

Yea, tôi nghĩ về điều đó, nhưng nó có vẻ như một cách không thực tế để làm điều đó, vì vậy tôi đã hy vọng có một cách khác. Nếu không ai có đề nghị nào khác, đó là điều tôi sẽ làm. –

+0

Đây là cách để làm điều đó, với một chức năng đệ quy đơn giản. – MusiGenesis

11

Bạn có thể sử dụng điều khiển PointToScreen phương pháp để có được vị trí tuyệt đối đối với các màn hình với.

Bạn có thể làm phương thức Biểu mẫu PointToScreen và với toán cơ bản, nhận vị trí của kiểm soát.

+0

Vâng, cảm ơn bạn. Hoàn hảo! –

+0

Điều đó sẽ không hoạt động chính xác, trừ khi bạn tính đến chiều cao của thanh tiêu đề và chiều rộng của đường viền của biểu mẫu. – MusiGenesis

+0

Làm cách nào để có được vị trí tuyệt đối của kiểm soát? Bạn phải truyền vào một đối tượng Point tới PointToScreen(), điều này không có ý nghĩa trong trường hợp này. – Tim

1

Trong thử nghiệm của tôi, cả hai giải pháp Fredrik Mork của Hans Kesting và đưa ra câu trả lời tương tự. Nhưng:

Tôi đã tìm thấy sự khác biệt thú vị trong câu trả lời bằng cách sử dụng các phương pháp của Raj More và Hans Kesting, và tôi nghĩ rằng tôi sẽ chia sẻ. Nhờ cả hai mặc dù cho sự giúp đỡ của họ; Tôi không thể tin rằng một phương pháp như vậy không được xây dựng trong khuôn khổ.

Xin lưu ý rằng Raj không viết mã và do đó việc triển khai của tôi có thể khác với ý của anh ấy.

Sự khác biệt tôi thấy là phương pháp từ Raj Nhiều hơn thường là hai pixel lớn hơn (trong cả X và Y) so với phương pháp từ Hans Kesting. Tôi chưa xác định tại sao điều này xảy ra. Tôi khá chắc chắn nó có một cái gì đó để làm với thực tế là có vẻ là một biên giới hai pixel xung quanh các nội dung của một hình thức Windows (như trong, bên trong biên giới ngoài cùng của biểu mẫu). Trong thử nghiệm của tôi, mà chắc chắn không phải là đầy đủ ở mức độ nào, tôi đã chỉ đi qua nó trên điều khiển được lồng nhau. Tuy nhiên, không phải tất cả các điều khiển lồng nhau đều thể hiện nó. Ví dụ, tôi có một TextBox bên trong một GroupBox thể hiện sự khác biệt, nhưng một Button bên trong cùng một GroupBox thì không. Tôi không thể giải thích tại sao.

Lưu ý rằng khi câu trả lời tương đương, họ xem điểm (0, 0) là bên trong đường viền nội dung tôi đã đề cập ở trên. Vì vậy, tôi tin rằng tôi sẽ xem xét các giải pháp từ Hans Kesting và Fredrik Mörk là chính xác nhưng không nghĩ rằng tôi sẽ tin tưởng vào giải pháp mà tôi đã thực hiện của Raj More.

Tôi cũng tự hỏi chính xác mã nào Raj More đã viết, vì anh đưa ra ý tưởng nhưng không cung cấp mã.Tôi không hiểu đầy đủ về phương pháp PointToScreen() cho đến khi tôi đọc bài đăng này: http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495

Đây là phương pháp thử nghiệm của tôi. Lưu ý rằng 'Phương pháp 1' được đề cập trong các nhận xét hơi khác so với phương pháp của 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; 
} 
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; 
    } 
} 
3

Lạ lùng thay, PointToClient và PointToScreen là không lý tưởng cho hoàn cảnh của tôi. Đặc biệt là vì tôi đang làm việc với các điều khiển ngoài màn hình không được liên kết với bất kỳ biểu mẫu nào. Tôi tìm thấy giải pháp của sahin hữu ích nhất, nhưng đã rút ra đệ quy và loại bỏ việc chấm dứt Biểu mẫu. Giải pháp bên dưới hoạt động đối với bất kỳ điều khiển nào của tôi có thể nhìn thấy được hay không, có chứa biểu mẫu hay không, được gắn kết hay không. Cảm ơn 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; 
} 
5

Supergeek, chức năng không đệ quy của bạn đã không tạo ra kết quả chính xác, nhưng không. Tôi tin rằng bạn không có quá nhiều bổ sung.

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

Tôi thường làm điều đó như thế này .. Làm việc mọi lúc ..

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

Đây phải là câu trả lời được chấp nhận! – skamlet

0

Đây là những gì tôi đã làm công việc giống như một nét duyên dáng

  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); 
     } 
Các vấn đề liên quan