web-dev-qa-db-ja.com

C#フォーム上のコントロールの位置を取得する

コントロールが他のコントロール(パネルなど)内にある場合に、フォーム内のコントロールの位置を取得する方法はありますか?

コントロールのLeftプロパティとTopプロパティは、親コントロール内の位置のみを提供しますが、コントロールが5つのネストされたパネル内にあり、フォーム上の位置が必要な場合はどうなりますか?

簡単な例:

ボタンbtnAは、パネルpnlB内の座標(10,10)にあります。
パネルpnlBは、frmCフォーム内の座標(15,15)にあります。

FrmCでのbtnAの位置(25,25)が必要です。

この場所を取得できますか?

63
Erlend D.

私は通常PointToScreenPointToClientを組み合わせます:

Point locationOnForm = control.FindForm().PointToClient(
    control.Parent.PointToScreen(control.Location));
88
Fredrik Mörk

コントロールPointToScreenメソッドを使用して、画面に対する絶対位置を取得できます。

Forms PointToScreenメソッドを実行し、基本的な数学でコントロールの位置を取得できます。

11
Raj More

私は通常、このようにします..毎回動作します..

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

フォームに到着するまで、親の中を歩いて、親の中の位置を確認できます。

編集:(未テスト)のようなもの:

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;
}
6
Hans Kesting

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

奇妙なことに、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;
}
3
BoeroBoy
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;
    }
}
1
sahin

私のテストでは、Hans KestingとFredrikMörkの両方のソリューションが同じ答えを出しました。しかし:

Raj MoreとHans Kestingの方法を使用して、答えに興味深い矛盾があることを発見し、共有すると思いました。彼らの助けに感謝します。このようなメソッドがフレームワークに組み込まれていないとは信じられません。

Rajはコードを記述しなかったため、私の実装は彼が意図したものとは異なる可能性があることに注意してください。

私が見つけた違いは、Raj Moreの方法がHans Kestingの方法よりも2ピクセル大きい(XとYの両方で)ことが多いことでした。私はこれがなぜ起こるかまだ決定していません。私はそれがWindowsフォームのcontentsの周りに2ピクセルのボーダーがあるように見えるという事実と何か関係があると確信しています(内、フォームの最も外側の境界内)。私のテストでは、決して徹底的なものではありませんでしたが、ネストされたコントロールでのみ遭遇しました。ただし、すべてのネストされたコントロールがそれを示すわけではありません。たとえば、GroupBox内に不一致を示すTextBoxがありますが、同じGroupBox内のButtonはそうではありません。理由を説明できません。

答えが同等である場合、ポイント(0、0)はinside上記のコンテンツ境界と見なされることに注意してください。したがって、Hans KestingとFredrikMörkのソリューションは正しいと考えますが、Raj Moreの実装したソリューションを信頼するとは思わないでしょう。

また、Raj Moreはアイデアを示したがコードを提供しなかったため、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;
}
1
Tyler Collier

これは私がやったことは魅力のように動作します

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