.NET TIPS

スクリーン座標←→クライアント座標の変換を行うには?

デジタルアドバンテージ 一色 政彦
2005/11/18
2005/12/12 更新

 Windowsが管理する座標系には次の2種類が存在する。

  • スクリーン座標
  • クライアント座標

 以下の画面は、これら2つの座標系を図示したものだ。

スクリーン座標とクライアント座標
Windowsの座標系はすべて左上隅の点を原点としており、座標軸のX軸は右方向が正、Y軸は下方向が正となる。Y軸が下に進むのは、数学における座標系と違ってコンピュータのGUIに独特なので注意すること。
  スクリーン座標。画面の左上隅の点を原点とした座標。
  フォームのクライアント座標。フォームの描画可能なクライアント領域の左上隅の点を原点とした座標。
  ボタンのクライアント座標。ボタンの描画可能なクライアント領域の左上隅の点を原点とした座標。

 スクリーン座標とは、画面の左上隅の点を基準とした絶対的な座標系である。

 一方のクライアント座標とは、Windowsアプリケーションが持つ「ウィンドウ領域」の中に含まれる描画可能な領域(これを「クライアント領域」と呼ぶ)を基準にした座標系である(ここではクライアント<座標>とクライアント<領域>という単語の違いに注意すること)。つまりクライアント座標は、クライアント領域の原点からの相対的な位置を示す座標系である(なお本稿ではクライアント領域とウィンドウ領域の違いの説明は割愛するが、詳しくは「TIPS:クライアント領域やウィンドウ領域の座標を取得するには?」を参照してほしい)。

 なおWindows OSレベルでは、デスクトップ上のGUI要素はすべてウィンドウとして管理されている。例えばボタンなどのコントロールも1つのウィンドウである。そのウィンドウそれぞれがクライアント領域を持っているため、すべてのウィンドウはクライアント座標を持っていることになる。

.NETアプリケーションでの座標の取り扱い

 このように.NETアプリケーションでは2種類の座標系が存在するわけだが、Windowsアプリケーションでの座標の取り扱いは、基本的にクライアント座標で行われる。このようになっているのは、Windowsアプリケーションでは基本的にクライアント領域内にしか描画やコントロールの配置などを行わないためだ。

 しかし.NETの一部のメソッドやプロパティでは、クライアント座標ではなく、スクリーン座標を取り扱うものがある。代表的なものでいえば、マウス・カーソルの座標などがそれである(マウス・カーソルの座標の扱いについては、「TIPS:カーソルの位置を取得・設定するには?」を参照してほしい)。

 このようなプロパティから取得したスクリーン座標の点(位置)の情報を、ウィンドウ内部の処理で使用する際には、それをいったんクライアント座標に変換しなければならないケースが非常に多い。これは、(前述したように)ウィンドウ内部の処理では、クライアント座標による計算が基本となっているからだ。また逆に、ウィンドウ内部のクライアント座標をこのようなプロパティに設定したい場合には、すべてスクリーン座標に変換したうえで行う必要がある。

スクリーン座標からクライアント座標に変換するには?

 実際にスクリーン座標の点(位置)をクライアント座標に変換するには、そのウィンドウのPointToClientメソッドを利用すればよい。例えば、スクリーン座標の点をフォームのクライアント座標に変換するには、フォームのPointToClientメソッドを呼び出せばよいし、スクリーン座標の点をボタンのクライアント座標に変換したい場合は、ボタンのPointToClientメソッドを呼び出せばよい。

 なおPointToClientメソッドは、パラメータにPoint型(System.Drawing名前空間)の値を取り、戻り値としてPoint型の値を返す。要するに、パラメータが変換前の座標で、戻り値が変換後の座標だ。

 以下のサンプル・プログラムは、このPointToClientメソッドの利用例である。このサンプル・プログラムでは、マウス・カーソルの位置をスクリーン座標で取得した後、フォームのクライアント座標とボタンのクライアント座標へ変換している。そしてそれぞれの座標をラベル・コントロール上に表示している。この一連の処理を10ミリ秒ごとに繰り返している(10ミリ秒ごとに処理を実行する方法の詳細は「TIPS:タイマにより一定時間間隔で処理を行うには?(Windowsタイマ編)」を参考にしていただきたい)。

private void timer1_Tick(object sender, System.EventArgs e)
{
  // マウス・カーソルのスクリーン座標での位置を取得
  label1.Text = Cursor.Position.ToString();

  // フォームを基準に(スクリーン座標を)クライアント座標に変換
  Point formClientCurPos = this.PointToClient(Cursor.Position);
  label2.Text = formClientCurPos.ToString();

  // ボタンを基準に(スクリーン座標を)クライアント座標に変換
  Point btnClientCurPos = button1.PointToClient(Cursor.Position);
  label3.Text = btnClientCurPos.ToString();
}
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles timer1.Tick
  ' マウス・カーソルのスクリーン座標での位置を取得
  label1.Text = Cursor.Position.ToString()

  ' フォームを基準に(スクリーン座標を)クライアント座標に変換

  Dim formClientCurPos As Point = Me.PointToClient(Cursor.Position)
  label2.Text = formClientCurPos.ToString()

  ' ボタンを基準に(スクリーン座標を)クライアント座標に変換
  Dim btnClientCurPos As Point = _
    button1.PointToClient(Cursor.Position)
  label3.Text = btnClientCurPos.ToString()
End Sub
スクリーン座標からクライアント座標に変換するサンプル・プログラム(上:C#、下:VB.NET)
PointToClientメソッドは、フォームや各種コントロールの基本クラスであるControlクラス(System.Windows.Forms名前空間)のメソッドである。ちなみにWin32 APIでは、この機能はScreenToClient関数により提供されていた。

 このサンプル・プログラムを実際に実行したのが次の画面である。この画面ではマウス・カーソルはボタン・コントロールの左上隅に位置している。

スクリーン座標からクライアント座標に変換するサンプル・プログラムの実行結果
マウス・カーソルの現在位置のスクリーン座標およびクライアント座標がリアルタイムに表示されている。マウス・カーソルはボタン・コントロールの左上隅に位置している。
  マウス・カーソルの現在位置のスクリーン座標。この例ではX座標は「173」、Y座標は「472」である。これは画面の左上隅の原点から173ピクセル右、472ピクセル下の場所に、マウス・カーソルが位置することを意味している。
  マウス・カーソルの現在位置のフォームを基準にした場合のクライアント座標。この例ではX座標は「16」、Y座標は「240」である。これはマウス・カーソルが、フォーム上の左上隅の点から右に16ピクセル、下に240ピクセルの場所に位置していることを意味する。
  マウス・カーソルの現在位置のボタンを基準にした場合のクライアント座標。X座標は「0」、Y座標も「0」である。つまりマウス・カーソルの位置は、ボタンのクライアント座標の原点にある。

クライアント座標からスクリーン座標に変換するには?

 逆にクライアント座標の点(位置)をスクリーン座標に変換するには、ウィンドウのPointToScreenメソッドを利用すればよい。例えば、フォームのクライアント座標の点をスクリーン座標に変換するにはフォームのPointToScreenメソッドを呼び出せばよいし、ボタンのクライアント座標の点をスクリーン座標に変換したい場合はボタンのPointToScreenメソッドを呼び出せばよい。

 なおPointToScreenメソッドも、先ほどのPointToClientメソッドと同様に、パラメータにPoint型(System.Drawing名前空間)の値を取り、戻り値としてPoint型の値を返す。パラメータが変換前の座標で、戻り値が変換後の座標だ。

 以下のサンプル・プログラムは、このPointToScreenメソッドの利用例である。このサンプル・プログラムでは、ボタンのクライアント座標の原点(左上隅の点)を取得した後、それをスクリーン座標へ変換したうえで、(座標の値を確認するためのメッセージボックスを表示してから)マウス・カーソルの位置として設定している。

private void button1_Click(object sender, System.EventArgs e)
{
  // ボタンのクライアント領域の原点を(クライアント座標で)取得
  Point btnClientLocation = button1.ClientRectangle.Location;

  // (ボタンを基準に)クライアント座標からスクリーン座標に変換
  // ※注意:ボタンのクライアント座標をスクリーン座標に
  //  変換するには、必ず<ボタンの>PointToScreenメソッドを使うこと
  Point btnScreenLocation =
    button1.PointToScreen(btnClientLocation);

  MessageBox.Show(
    "ボタンのクライアント領域の原点は、\n\n" +

    "クライアント座標では" +
    btnClientLocation.ToString() +
    "になり、\n\n" +

    "スクリーン座標では" +
    btnScreenLocation.ToString() +
    "になる。");

  // カーソルの位置をボタンの原点に移動
  Cursor.Position = btnScreenLocation;
}
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
  ' ボタンのクライアント領域の原点を(クライアント座標で)取得
  Dim btnClientLocation As Point = button1.ClientRectangle.Location

  ' (ボタンを基準に)クライアント座標からスクリーン座標に変換
  ' ※注意:ボタンのクライアント座標をスクリーン座標に
  '  変換するには、必ず<ボタンの>PointToScreenメソッドを使うこと
  Dim btnScreenLocation As Point = _
    button1.PointToScreen(btnClientLocation)

  MessageBox.Show( _
    "ボタンのクライアント領域の原点は、" & vbLf & vbLf & _
_
    "クライアント座標では" & _
    btnClientLocation.ToString() & _
     "になり、" & vbLf & vbLf & _
_
    "スクリーン座標では" & _
    btnScreenLocation.ToString() & _
    "になる。")


  ' カーソルの位置をボタンの原点に移動
  Cursor.Position = btnScreenLocation
End Sub
クライアント座標からスクリーン座標に変換するサンプル・プログラム(上:C#、下:VB.NET)
PointToScreenメソッドは、フォームや各種コントロールの基本クラスであるControlクラス(System.Windows.Forms名前空間)のメソッドである。ちなみにWin32 APIでは、この機能はClientToScreen関数により提供されていた。

 これを実際に実行したのが次の画面である。この画面はメッセージボックスが表示されたところである。サンプル・プログラムではこのメッセージボックスを閉じると、ボタンの原点の位置にマウス・カーソルが移動する。

クライアント座標からスクリーン座標に変換するサンプル・プログラムの実行結果
このメッセージボックスでは、クライアント座標とスクリーン座標におけるボタンの左上隅の座標が表示されている。このメッセージボックスを閉じると、マウス・カーソルがボタンの左上隅の原点に移動する。。
  ボタンの左上隅の原点のクライアント座標は、当然ながら、常にX座標が「0」、Y座標が「0」になる。
  ボタンの左上隅の原点のスクリーン座標は、ウィンドウが表示されている場所によって変化する。この例ではX座標は「173」、Y座標は「472」である。これはスクリーンの左上隅の点から173ピクセル右、472ピクセル下の場所に、ボタンの左上隅の原点が位置することを意味している。

 以上のサンプル・プログラム全体のコードは、次のリンクからダウンロードできる。

 なおPointToClientメソッドやPointToScreenメソッドを使用する場合には、どのウィンドウ(フォームやコントロール)のメソッドを呼び出すかに注意する必要がある。ボタンのPointToScreenメソッドを呼び出すべきところで、間違えてフォームのものを呼び出してしまうと、座標系が違うので当然ながら値も異なってくる。

 ちなみに点(Point型の値)ではなく四角の領域(Rectangle型の値)をスクリーン座標系やクライアント座標系に変換するメソッドも用意されている。領域をスクリーン座標系に変換するのはウィンドウのRectangleToScreenメソッドで、クライアント座標系に変換するのはウィンドウのRectangleToClientメソッドだ。End of Article

カテゴリ:Windowsフォーム 処理対象:ウィンドウ
使用ライブラリ:Point構造体(System.Drawing名前空間)
使用ライブラリ:Rectangle構造体(System.Drawing名前空間)
使用ライブラリ:Controlクラス(System.Windows.Forms名前空間)
関連TIPS:タイマにより一定時間間隔で処理を行うには?(Windowsタイマ編)
関連TIPS:クライアント領域やウィンドウ領域の座標を取得するには?
関連TIPS:カーソルの位置を取得・設定するには?

この記事と関連性の高い別の.NET TIPS
クライアント領域やウィンドウ領域の座標を取得するには?
マウス・カーソルの位置を取得・設定するには?
ある座標や領域がコントロールの領域内に含まれているかを確認するには?
スクリーンやウィンドウをキャプチャするには?
マウス・カーソルの移動可能領域を制限するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

Insider.NET 記事ランキング

本日 月間
ソリューションFLASH