「TIPS:スクリーン座標←→クライアント座標の変換を行うには?」では、スクリーン座標とクライアント座標の違いを説明し、両者間で座標を相互の座標系の値に変換する方法を説明した。その中で、クライアント座標とは、Windowsアプリケーションが持つ「ウィンドウ領域」の中に含まれる描画可能な領域(クライアント領域)を基準にした座標系であると説明した(ここではクライアント<座標>とクライアント<領域>という単語の違いに注意すること)。それではこのウィンドウ領域とクライアント領域は、どこが違うのだろうか。これらの領域は、.NETプログラミングではどのようにして取得すればよいのだろうか。本稿ではこれらの内容について解説する。OSレベルでは、デスクトップ上のGUI要素はすべてウィンドウとして管理されている。ボタンなどのコントロールも1つのウィンドウである。このウィンドウ全域がウィンドウ領域である。ウィンドウ領域を求めることは、ウィンドウ内部とその外部との境界領域(Bounds)を求めることに等しい。各ウィンドウは、それぞれその内部に(プログラマーが自由にコントロールを配置したり、描画したりすることが可能な)クライアント領域を持っている。クライアント領域以外の部分(スクロール・バーや、境界線、タイトル・バー、メニュー・バーなど)は「非クライアント領域」と呼ばれる。「ウィンドウ領域」は「クライアント領域」+「非クライアント領域」で成り立っている。次の画面では、このウィンドウ領域とクライアント領域の違いが示されている。ウィンドウ領域とクライアント領域の違いウィンドウ内部と外部の境界領域が「ウィンドウ領域」(Bounds)で、ウィンドウ領域内のプログラムから描画可能な部分が「クライアント領域」(ClientRectangle)である。(1)フォームのクライアント領域。境界線やタイトル・バーなどの要素を除いた領域で、プログラムから描画可能な領域である。(2)フォームのウィンドウ領域。クライアント領域に境界線やタイトル・バーなどの要素を含めた領域で、外部との境界となる領域である。(3)ボタンのクライアント領域。ボタンの場合は境界線やタイトル・バーなどの要素がないため(4)のウィンドウ領域と同じになる。(4)ボタンのウィンドウ領域。それでは、これらのクライアント領域とウィンドウ領域(のサイズおよび位置)を、実際にプログラムから取得してみよう。本稿では、それぞれのウィンドウのクライアント座標により、これらの領域の値を取得する。クライアント領域を取得するには?まずはフォームやコントロールなどのウィンドウのクライアント領域を取得しよう。これには、ウィンドウのClientRectangleプロパティ(データ型はRectangle型)を参照すればよい。ちなみにこのプロパティは、読み取り専用で設定はできない。以下のサンプル・コードは、実際にClientRectangleプロパティを活用してウィンドウのクライアント領域を取得するメソッドである。このメソッドのパラメータにボタンなどのコントロールもしくはフォームのオブジェクトを指定して呼び出すと、その戻り値としてクライアント領域をRectangle型で取得することができる。0)(つまり、X座標が「0」、Y座標が「0」)である。「クライアント領域のサイズ」(=ClientRectangle.Sizeプロパティ)はよく使われるため、わざわざClientRectangleプロパティを呼び出さなくても、ウィンドウのClientSizeプロパティで直接取得することもできる。上記コード中の「//////......」で囲まれている部分のコードは、この2つの内容を検証するためのデバッグ・コードである。ここで使われているDebugクラス(System.Diagnostics名前空間)の静的なAssertメソッドは、パラメータの(条件式の)値がfalseのときに、警告メッセージ(=Assert)を表示させるためのものだ。ちなみに、このClientSizeプロパティは読み取り専用ではないため、値を設定することも可能だ。このプロパティからクライアント領域のサイズを指定することができるわけだ。ClientSizeプロパティによりクライアント領域のサイズを指定した場合、そのクライアント領域を持つウィンドウ領域のサイズも自動的に変更される。フォームのロード時に次のようなコードを呼び出すとしよう。XP上の筆者の環境の場合。ウィンドウ領域のサイズはOS環境によって異なる可能性がある)。ウィンドウ領域を取得・設定するには?次にフォームやコントロールなどのウィンドウのウィンドウ領域を取得してみよう。これには、ウィンドウのBoundsプロパティ(データ型はRectangle型)を参照すればよい。ちなみにこのプロパティは、取得だけでなく設定も可能である。このBoundsプロパティのウィンドウ領域の値は、そのウィンドウがフォームかコントロールかによって意味(座標系)が異なるので注意が必要だ。フォームの場合、Boundsプロパティの値は<スクリーン座標>で取得される。このため、先ほどのメソッドなどで取得した「フォームのクライアント領域」と比較するならば、フォームのクライアント座標へ変換する必要がある。この変換方法は、前掲のTIPSで紹介したとおりだ。本稿では説明を割愛する。対してコントロールの場合、Boundsプロパティの値は<親コンテナのクライアント座標>で取得される。従って、先ほどのメソッドなどで取得した「ボタンのクライアント領域」と比較するならば、いったん(<親コンテナ>のクライアント座標から)スクリーン座標に変換して、それをさらに<ボタン>のクライアント座標に変換する必要がある。ちなみに親コンテナは、そのコントロールのParentプロパティからControlクラス(System.Windows.Forms名前空間)のオブジェクトとして取得できる。フォーム上に直接コントロールを配置した場合は、そのコントロールの親コンテナはそのフォームである。パネルなどのコンテナ上にコントロールを配置すれば、そのコンテナが親コンテナとなる。以上の内容を実際に実装したのが、次のサンプル・コードのメソッドである。このメソッドでは、そのパラメータにボタンなどのコントロールもしくはフォームのオブジェクトを指定して呼び出すと、その戻り値としてウィンドウ領域をRectangle型で取得することができる。Functionウィンドウのウィンドウ領域を取得するメソッド(上:C#、下:VB.NET)コード中にあるis演算子(C#)やTypeOf〜Is演算子(VB.NET)は、オブジェクトがその型に属するかどうかをBool値(Boolean)で返すためのものだ。「ウィンドウ領域の左上隅の原点」(=Bounds.Locationプロパティ)は、スクリーン上でのフォームの位置を指定したり、フォームなどの親コンテナ上でのコントロールの位置を指定したりするのに使われるので、簡単に取得・設定するためのLocationプロパティが用意されている。「ウィンドウ領域のサイズ」(=Bounds.Sizeプロパティ)も同様によく使われるため、ウィンドウのSizeプロパティで取得・設定できるようになっている。先ほどのメソッドと同じように、上記コード中の「//////......」で囲まれているコードは、これらの内容を検証するためのものだ。コントロールのサイズ指定では、通常はこのSizeプロパティが用いられる。フォームのサイズ指定の場合はSizeプロパティではなく、前述したClientSizeプロパティが用いられることが一般的だ。これは、Windowsフォームのデザインをするうえで実際にコントロールなどを配置したり描画したりできる「フォームのクライアント領域」のサイズを指定した方が、開発者にとってより扱いやすいからだろう。以上で説明した「クライアント領域を取得するメソッド」と「ウィンドウ領域を取得するメソッド」のサンプル・コードを実際に利用して、そこで得た領域情報をラベルに設定しているのが、次のサンプル・プログラムだ。ソース・コード全体は、このサンプル・プログラムの説明欄のリンク(下の「C#版のダウンロード」「VB.NET版のダウンロード」)からダウンロードできる。Subクライアント領域とウィンドウ領域の情報をラベルに表示するサンプル・プログラムC#版のダウンロード(Form1.cs)VB.NET版のダウンロード(Form1.vb)このサンプル・プログラムを実行すると、冒頭で示した画面のサンプル・アプリケーションが実行される。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。