Locationプロパティ、PointToScreen、PointToClient メソッドの使い方

　ControlのLocationメソッド、PointToScreenメソッド、そしてPointToClientメソッドの使い方をまとめる。本記事では、特に下の写真－１のように複数のControl(ここではPanel)が入れ子上になっている状態での、あるコントロールの座標を他のコントロールの座標系で表す方法について重点を置く。

![スクリーンショット２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/487c5b8c-7c00-8537-f0e3-e2e980392dbc.png)
　　　　　　　　　　　　　　　　　　　　　　　写真－１　

**０．前提条件**
　上の写真－１では、フォームの上にpanel1から4までのパネルが計４枚配置されている。それぞれの関係は次のとおり、フォームの上にpanel1(黄色)とpanel4(ライトグリーン）の二枚のパネルが配置され、さらにpanel1の上にpanel2(水色）が一枚配置され、そのpanel2のパネルの上にpanel3(ピング)が一枚配置されている。

```C#
            this.Controls.Add(panel1);    // フォーム(this)上にパネルpanel1(黄色)を追加
            this.Controls.Add(panel4);    // フォーム(this)上にパネルpanel4(ライトグリーン)を追加

            panel1.Controls.Add(panel2);  // panel1(黄色)の上にパネルpanel2(水色)を追加

            panel2.Controls.Add(panel3);  // panel2(水色)の上にパネルpanel3(ピンク)を追加
```

**１．座標系**
　この写真－１のスクリーン（モニタ）画面の中には、下の写真－２のように６つの座標系が含まれている。
　　　　　ａ．スクリーン（モニタ）の座標系
　　　　　ｂ．フォーム(this)の座標系
　　　　　ｃ．panel1の座標系
　　　　　ｄ．panle2の座標系
　　　　　ｅ．panel3の座標系
　　　　　ｆ．panel4の座標系
　　
　それぞれの座標系は、それぞれの領域の左上が原点になり、またそれぞれの座標軸の方向に従って座標を持つ。


![スクリーンショット３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/44d385d2-7c56-5720-604f-4dd5b3947904.png)
　　　　　　　　　　　　　　　　　　　　　　　写真－２

**２．Locationプロパティで得られる値**
　写真－２において、それぞれのコントロール（panel1～4）のLocationプロパティで得られる値は、その親の座標系で表される値である。すなわち、
　　　panel1.Locationであれば、フォーム(this)の座標系であり、
　　　panel2.Locationであれば、panel1の座標系、
　　　panel3.locationであれば、panel2の座標系になる。
　また、
　　　panel4.Locationであれば、前提条件からこれもpanel1同様フォーム(this)の座標系になる。
　　
　実際にその使い方は、

```C#
Point p11 = panel1.Location;    // フォーム(this)の座標系で表された位置
Point p21 = panel2.Location;    // panel1の座標系で表された位置
Point p31 = panel3.Location;    // panel2の座標系で表された位置
Point p41 = panel4.Location;    // フォーム(this)の座標系で表された位置
```

**３．PointToScreenメソッドの使い方**
　PointToScreenメソッドは、あるコントロールの座標系で表された点の位置を、スクリーン（モニタ）の左上を原点(0,0)とした座標系に変換するメソッドである。
　基本的な使い方は、

```C#
Point p = 点が含まれるコントロールのオブジェクト.PointToScreen(点が含まれるコントロールの座標系で表された座標);
```

　例えば写真－２を例に挙げるならば、panel1の(左上の角の)位置をスクリーンの座標系で表す時は、次のようになる

```C#
Point p11 = panel1.Location;            // panel1の左上の座標をフォーム(this)の座標系で表した点p11
Point p12 = this.PointToScreen(p11);    // 点p11をスクリーンの座標系で表した座標p12 
```

　また、panel2の位置をスクリーン座標系で表す時は、

```C#
Point p21 = panel2.Location                // panel2の左上の座標をpanel1の座標系で表した点p21
Point p22 = panel1.PointToScreen(p21);     // 点p21をスクリーンの座標系で表した座標p22
```

　ここで、注意しなければならないのは、PointToScreen()の前のオブジェクトは、PointToScreen()のパラメータに与えられる点が含まれるオブジェクトでなければならないことである。すなわち繰り返しになるが、panel1(の左上の点)が含まれるおbジェクトはフォーム(this)オブジェクトであり、またpanel2の(左上の点）が含まれるのはpanel1であるから、上記のような記述になる。
　では、panel3は、どのように記述されるであろうか。panel3のコントロールの親のコントロールはpanel2であるから、スクリーン座標系でpanel3の位置を表すと、

```C#
Point p31 = panel3.Location;             // panel3の左上の座標をpanel2の座標系で表した点p31
Point p32 = panel2.PointToScreen(p31);   // 点p31をスクリーンの座標系で表した座標p32
```

となる。

　それならばpanel4の場合は、親がpanel1と同様にフォーム(this)であるから、

```C#
Point p41 = panel4.Location;           // panel4の左上の座標をフォーム(this)の座標系で表した点p41
Point p42 = this.PointToScreen(p41);   // 点p41をスクリーンの座標系で表した座標p42
```
となる。

**４．PointToClientメソッド**
　PointToClientメソッドは、スクリーン座標系で表された(コントロールの左上の角の)点を、別のコントロールの座標系に変換するメソッドである。
　基本的な使い方は、

```C#
Point p = 表したい座標系を持つコントロールのオブジェクト.PointToClient(知りたい点のスクリーン座標)
```

　また写真－２を例に挙げて説明する。
　panel1の(左上の角の)位置を、Locationプロパティで表したフォームの座標系、PointToScreenメソッドで用いたスクリーンの座標系、スクリーン座標をPointToClientメソッドでフォームの座標系で表した例を示す。

```C#
Point p11 = panel1.Location;            // panel1の左上の座標をフォーム(this)の座標系で表した点p11
Point p12 = this.PointToScreen(p11);    // 点p11をスクリーンの座標系で表した座標p12 
Point p13 = this.PointToClient(p12);    // スクリーン座標で表されたp12をフォーム(this)の座標系に変換する
```
　こので注意しなければならないのは、PointToClientメソッドの前のオブジェクトは、表したい座標系のオブジェクトでなければならないのであり、この場合はフォームを表すthisでなければならない。

　次にpanel2の(左上の角の)位置を、Locationプロパティで表したフォームの座標系、PointToScreenメソッドで用いたスクリーンの座標系、スクリーン座標をPointToClientメソッドでフォームの座標系、panel1の座標系、panel2の座標系に変換して表した例を示す。

```C#
Point p21 = panel2.Location                 // panel2の左上の座標をpanel1の座標系で表した点p21
Point p22 = panel1.PointToScreen(p21);      // 点p21をスクリーンの座標系で表した座標p22
Point p23 = this.PointToClient(p22);        // 点p22をフォーム(this)の座標系で表した座標p23
Point p24 = panel1.PointToClient(p22);      // 点p21をpanel1の座標系で表した座標p24
Point p25 = panel2.PointToClient(p22);      // 点p21をpanel2の座標系で表した座標p25
```

　ここで注意しなければならないのは、panel2の左上の点をpanel2の座標系で表した点p25は、その座標が(0,0)になることである。（当然の話ではあるが、、、）

　さらに次に、panel4をpanel1からpanel3の座標系で表す例を示す。panel4は、panel1同様、前提条件からフォーム(this)に属している。しかし、panel2とpanel3とは、直接的な関係はない。しかし、一方でスクリーン座標系を通して変換することができる。

```C#
Point p41 = panel4.Location;                // panel2の左上の座標をフォーム(this)の座標系で表した点p41
Point p42 = this.PointToScreen(p41);        // 点p41をスクリーンの座標系で表した座標p42
Point p44 = panel1.PointToClient(p42);      // 点p42をpanel1の座標系で表した座標p44
Point p45 = panel2.PointToClient(p42);      // 点p42をpanel2の座標系で表した座標p45
Point p46 = panel3.PointToClient(p42);      // 点p42をpanel3の座標系で表した座標p46
```

**４．以上をまとめたソースコード**
　以上をまとめたソースコードを次に示す。コンパイルすると写真－１で示したフォームの実行ファイルができる。それを起動し、そのフォームをドラッグして動かすと、スクリーン座標系で表されたコントロールの座標の値が変わる。またスクリーン座標をPointToClientメソッドそれぞれの座標系に変換された座標が表示される。

　　　　　　　　　　　　　　　   　ソースコード

```C#:ToScreenToClient.cs
using System;
using System.Drawing;
using System.Windows.Forms;

namespace ToScreenMethod
{
    class Form1 : Form
    {
        Panel panel1;
        Label label11, label12, label13, label14, label15;
        Point p11, p12, p13, p14;

        Panel panel2;
        Label label21, label22, label23, label24, label25, label26;
        Point p21, p22, p23, p24, p25;

        Panel panel3;
        Label label31, label32, label33, label34, label35, label36, label37;
        Point p31, p32, p33, p34, p35, p36;

        Panel panel4;
        Label label41, label42,label43, label44,label45,label46, label47;
        Point p41, p42, p43, p44, p45, p46;

        public static void Main()
        {
            Application.Run(new Form1());
        }

        public Form1()
        {
            // 
            // label41を定義
            label41 = new Label();
            label41.Location = new Point(0, 0);
            label41.AutoSize = true;

            // label42を定義
            label42 = new Label();
            label42.Location = new Point(0, label41.Height);
            label42.AutoSize = true;

            // label43を定義
            label43 = new Label();
            label43.AutoSize = true;
            label43.Location = new Point(0, label42.Location.Y + label42.Height);

            // label44を定義
            label44 = new Label();
            label44.AutoSize = true;
            label44.Location = new Point(0, label43.Location.Y + label43.Height);
            
            // label45を定義
            label45 = new Label();
            label45.AutoSize = true;
            label45.Location = new Point(0, label44.Location.Y + label44.Height);
            
            // label46を定義
            label46 = new Label();
            label46.AutoSize = true;
            label46.Location = new Point(0, label45.Location.Y + label45.Height);
            
            // label47を定義
            label47 = new Label();
            label47.AutoSize = true;
            label47.Location = new Point(0, label46.Location.Y + label46.Height);

            // panel4を定義
            panel4 = new Panel();
            panel4.Location = new Point(50, 700);
            panel4.Size = new Size(1100, 200);
            panel4.BorderStyle = BorderStyle.None;
            panel4.BackColor = Color.LightGreen;
            panel4.Controls.Add(label41);
            panel4.Controls.Add(label42);
            panel4.Controls.Add(label43);
            panel4.Controls.Add(label44);
            panel4.Controls.Add(label45);
            panel4.Controls.Add(label46);
            panel4.Controls.Add(label47);

            //
            // label31を定義
            label31 = new Label();
            label31.Location = new Point(0, 0);
            label31.AutoSize = true;

            // label32を定義
            label32 = new Label();
            label32.Location = new Point(0, label31.Height);
            label32.AutoSize = true;

            // label33を定義
            label33 = new Label();
            label33.AutoSize = true;
            label33.Location = new Point(0, label32.Location.Y + label32.Height);

            // label34を定義
            label34 = new Label();
            label34.AutoSize = true;
            label34.Location = new Point(0, label33.Location.Y + label33.Height);

            // label35を定義　
            label35 = new Label();
            label35.AutoSize = true;
            label35.Location = new Point(0, label34.Location.Y + label34.Height);

            // label36を定義
            label36 = new Label();
            label36.AutoSize = true;
            label36.Location = new Point(0, label35.Location.Y + label35.Height);
            
            // label37を定義
            label37 = new Label();
            label37.AutoSize = true;
            label37.Location = new Point(0, label36.Location.Y + label36.Height);

            // panel3を定義
            panel3 = new Panel();
            panel3.Location = new Point(50, 150);
            panel3.Size = new Size(900, 200);
            panel3.BorderStyle = BorderStyle.None;
            panel3.BackColor = Color.Pink;
            panel3.Controls.Add(label31);
            panel3.Controls.Add(label32);
            panel3.Controls.Add(label33);
            panel3.Controls.Add(label34);
            panel3.Controls.Add(label35);
            panel3.Controls.Add(label36);
            panel3.Controls.Add(label37);

            //
            // label21を定義
            label21 = new Label();
            label21.Location = new Point(0, 0);
            label21.AutoSize = true;

            // label22を定義
            label22 = new Label();
            label22.Location = new Point(0, label21.Height);
            label22.AutoSize = true;

            // label23を定義
            label23 = new Label();
            label23.AutoSize = true;
            label23.Location = new Point(0, label22.Location.Y + label22.Height);

            // label24を定義
            label24 = new Label();
            label24.AutoSize = true;
            label24.Location = new Point(0, label23.Location.Y + label23.Height);

            // label25を定義　
            label25 = new Label();
            label25.AutoSize = true;
            label25.Location = new Point(0, label24.Location.Y + label24.Height);
            
            // label26を定義
            label26 = new Label();
            label26.AutoSize = true;
            label26.Location = new Point(0, label25.Location.Y + label25.Height);

            // panel2を定義
            panel2 = new Panel();
            panel2.Location = new Point(50, 150);
            panel2.Size = new Size(1000, 400);
            panel2.BorderStyle = BorderStyle.None;
            panel2.BackColor = Color.Aqua;
            panel2.Controls.Add(label21);
            panel2.Controls.Add(label22);
            panel2.Controls.Add(label23);
            panel2.Controls.Add(label24);
            panel2.Controls.Add(label25);
            panel2.Controls.Add(label26);
            panel2.Controls.Add(panel3);  // panel2の上にパネルpanel3を追加

            // 
            // label11を定義
            label11 = new Label();
            label11.Location = new Point(0, 0);
            label11.AutoSize = true;

            // label12を定義
            label12 = new Label();
            label12.Location = new Point(0, label11.Height);
            label12.AutoSize = true;

            // label13を定義
            label13 = new Label();
            label13.AutoSize = true;
            label13.Location = new Point(0, label12.Location.Y + label12.Height);

            // label14を定義
            label14 = new Label();
            label14.AutoSize = true;
            label14.Location = new Point(0, label13.Location.Y + label13.Height);

            // label15を定義
            label15 = new Label();
            label15.AutoSize = true;
            label15.Location = new Point(0, label14.Location.Y + label14.Height);

            // panel1を定義
            panel1 = new Panel();
            panel1.Location = new Point(50, 50);
            panel1.Size = new Size(1100, 600);
            panel1.BorderStyle = BorderStyle.None;
            panel1.BackColor = Color.Yellow;
            panel1.Controls.Add(label11);
            panel1.Controls.Add(label12);
            panel1.Controls.Add(label13);
            panel1.Controls.Add(label14);
            panel1.Controls.Add(label15);
            panel1.Controls.Add(panel2);  // panel1の上にパネルpanel2を追加

            //
            // フォームを定義
            this.Width = 1200;
            this.Height = 950;
            this.Text = "ToScreenToClient";
            this.Controls.Add(panel1);  // フォーム(this)上にパネルpanel1を追加
            this.Controls.Add(panel4);  // フォーム(this)上にパネルpanel4を追加

            // イベントハンドラを登録
            this.LocationChanged += new EventHandler(Form1_LocationChanged);    // フォームが移動したことを検出

        }

        //フォームを移動した時に実行
        private void Form1_LocationChanged(object sender, EventArgs e)
        {
            //panel1
            label11.Text = "panel1の左上の座標";

            p11 = panel1.Location;
            label12.Text = "(1) panel1.Locationで示される座標(" + p11.X + "," + p11.Y + ")";

            p12 = this.PointToScreen(p11);  
            label13.Text = "(2) this.PointToScreen( (1)の座標系 ) で求められたスクリーン(モニタ)の左上を基準にした座標(" + p12.X + "," + p12.Y + ") <--- フォームをドラッグして動かすと、座標の表示が変わります。";

            p13 = this.PointToClient(p12);
            label14.Text = "(3) this.PointToClient( (2)のスクリーン座標系 ) で求められたフォーム(this)の左上を基準にした座標(" + p13.X + "," + p13.Y + ")     フォームを動かしても、(1)と同じ値。";

            p14 = panel1.PointToClient(p12);
            label15.Text = "(3) panel1.PointToClient( (2)のスクリーン座標系 ) で求められたpanel1の左上を基準にした座標(" + p14.X + "," + p14.Y + ")";


            //panel2
            label21.Text = "panel2の左上の座標";

            p21 = panel2.Location;
            label22.Text = "(1) Locationメソッドで示される座標(" + p21.X + "," + p21.Y + ")";

            p22 = panel1.PointToScreen(p21);  
            label23.Text = "(2) panel1.PointToScreen( (1)の座標系 ) で求められたスクリーン(モニタ)の左上を基準にした座標(" + p22.X + "," + p22.Y + ") <--- フォームをドラッグして動かすと、座標の表示が変わります。";

            p23 = this.PointToClient(p22);  
            label24.Text = "(3) this.PointToClient( (2)のスクリーン座標系 ) で求められたフォーム(this)の左上を基準にした座標(" + p23.X + "," + p23.Y + ") ";

            p24 = panel1.PointToClient(p22);
            label25.Text = "(4) panel1.PointToClient( (2)のスクリーン座標系 ) で求められたpanel1の左上を基準にした座標(" + p24.X + "," + p24.Y + ")     フォームを動かしても、(1)と同じ値。";

            p25 = panel2.PointToClient(p22);
            label26.Text = "(5) panel2.PointToClient( (2)のスクリーン座標系 ) で求められたpanel2の左上を基準にした座標(" + p25.X + "," + p25.Y + ")";


            //panel3
            label31.Text = "panel3の左上の座標";

            p31 = panel3.Location;
            label32.Text = "(1) Locationメソッドで示される座標(" + p31.X + "," + p31.Y + ")";

            p32 = panel2.PointToScreen(p31); 
            label33.Text = "(2) panel2.PointToScreen( (1)の座標系 ) で求められたスクリーン(モニタ)の左上を基準にした座標(" + p32.X + "," + p32.Y + ") <--- フォームをドラッグして動かすと、座標の表示が変わります。";

            p33 = this.PointToClient(p32);  
            label34.Text = "(3) this.PointToClient( (2)のスクリーン座標系 ) で求められたフォーム(this)の左上を基準にした座標(" + p33.X + "," + p33.Y + ") ";

            p34 = panel1.PointToClient(p32);
            label35.Text = "(4) panel1.PointToClient( (2)のスクリーン座標系 ) で求められたpanel1の左上を基準にした座標(" + p34.X + "," + p34.Y + ")";

            p35 = panel2.PointToClient(p32);
            label36.Text = "(5) panel2.PointToClient( (2)のスクリーン座標系 ) で求められたpanel2の左上を基準にした座標(" + p35.X + "," + p35.Y + ")     フォームを動かしても、(1)と同じ値。";

            p36 = panel3.PointToClient(p32);
            label37.Text = "(6) panel3.PointToClient( (2)のスクリーン座標系 ) で求められたpanel3の左上を基準にした座標(" + p36.X + "," + p36.Y + ")";


            //panel4
            label41.Text = "panel4の左上の座標";

            p41 = panel4.Location;
            label42.Text = "(1) Locationメソッドで示される座標(" + p41.X + "," + p41.Y + ")";

            p42 = this.PointToScreen(p41);
            label43.Text = "(2) this.PointToScreen( (1)の座標系 ) で求められたスクリーン(モニタ)の左上を基準にした座標(" + p42.X + "," + p42.Y + ") <--- フォームをドラッグして動かすと、座標の表示が変わります。";

            p43 = this.PointToClient(p42);
            label44.Text = "(3) this.PointToClient( (2)のスクリーン座標系 ) で求められたフォーム(this)の左上を基準にした座標(" + p43.X + "," + p43.Y + ")      フォームを動かしても、(1)と同じ値。";

            p44 = panel1.PointToClient(p42);
            label45.Text = "(4) panel1.PointToClient( (2)のスクリーン座標系 ) で求められたpanel1の左上を基準にした座標(" + p44.X + "," + p44.Y + ")";

            p45 = panel2.PointToClient(p42);
            label46.Text = "(5) panel2.PointToClient( (2)のスクリーン座標系 ) で求められたpanel2の左上を基準にした座標(" + p45.X + "," + p45.Y + ")";

            p46 = panel3.PointToClient(p42);
            label47.Text = "(6) panel3.PointToClient( (2)のスクリーン座標系 ) で求められたpanel3の左上を基準にした座標(" + p46.X + "," + p46.Y + ")";

        }

    }
}

```

以上