|
2-2-2. ウィンドウの機能と各部の名称
ここでは、ウィンドウの機能と各部の名称を説明します。
ウィンドウの種類
ウィンドウは、大きくいくつかの種類に分類できます。本来見えかたと用途は関係無いのですが、通常は用途によって表示の形式を決定します。
- オーバーラップウィンドウ
- オーバーラップウィンドウとは、タイトルバー、境界、およびクライアント領域を持つ、トップレベルウィンドウのことです。このウィンドウはアプリケーションのメインウィンドウとして機能します。また、オーバーラップウィンドウは、コントロールメニュー、アイコン化ボタン、最大表示ボタン、およびスクロールバーを持つこともできます。普通は上の図に様な表示を行ない、クローズボタンを押すかメニューで終了を実行するまで存在します。
- ポップアップウィンドウ
- ポップアップウィンドウとは、オーバーラップウィンドウの特殊なもので、通常はダイアログボックスやメッセージボックスなどの様にアプリケーションのメインウィンドウの外部に、一時的に表示されるウィンドウとして使われます。ポップアップウィンドウでは、メニューは無く、タイトルバーは省略可能です。普通は、ポップアップウィンドウが表示されている間は、他のウィンドウの操作はできません。
- 子ウィンドウ
- 子ウィンドウは、上記のオーバーラップウィンドウや、ポップアップウィンドウのクライアントエリア内に作成するウィンドウです。子ウィンドウは親のエリア内にしか表示できません。この様に子ウィンドウの一部機能は、親ウィンドウに依存します。また子ウィンドウ内にさらに子ウィンドウを作成することも可能です。ツールバーやステータスバーを含めた、すべてのコントロールは、子ウィンドウです。子ウィンドウは、普通はタイトルやメニューを表示しません。ただし、MDIで使用するウィンドウも一種の子ウィンドウな様に、例外は多くあります。よって子ウィンドウと言う概念は、ウィンドウの機能や見えかたよりも、親子関係を説明する言葉と捕らえるべきでしょう。
ウィンドウの名称
ウィンドウの名称の図
オーバーラップウィンドウの各部の名称を上に示します。最上にはタイトルバーがあり、左からコントロールメニュー、タイトル、最小化ボタン、最大化ボタン、クローズボタンと配置されます。最小化ボタンは、アイコン化ボタンとも言います。タイトルの下は、メニュバーがあります。メニューバーには、ファイルや編集のメニューがあり、操作するとサブメニューがポップアップします。MDIの場合は、メニューバーにMDI子ウィンドウを操作するボタンが追加されます。
タイトルバーとメニューバー以外の、ウィンドウの大部分の領域をクライアントアリアといいます。アプリケーションは、このエリアに機能を組み込んだウィンドウを作成します。上図の例では、上にツールバー、下にステータスバー、そして左にツリービュー、右にリッチテキストのコモンコントロールのウィンドウを配置しています。現在では、たいていのアプリケーションは、ツールバーとステータスバーは付いています。またツリービューとリッチテキストコントロールの様に、水平と垂直のスクロールバーをウィンドウには付加できます。
ウィンドウの一番の外側の枠は、サイズ変更境界といいます。ウィンドウによってはリサイズができないものはありますが、たいていはここをドラッグしてウィンドウのサイズを変更します。
ウィンドウのエリア
- クライアントエリア (client area)
- アプリケーションが、テキストやグラフィックスを出力するウィンドウ部分です。GetClientRect 関数でその大きさを得ます。
- 非クライアントエリア (nonclient area)
- ウィンドウのクライアント領域以外の部分を言います。ウィンドウの非クライアント領域には、境界、メニューバー、タイトルバー、コントロールメニュー、最小化ボタン、および最大化ボタンなどのパーツがあります。しかしこれらのパーツはすべてオプションで、子ウィンドウなどは、すべて無い場合もあります。このエリアに関するメッセージは、WM_NCxxx と言う名称が付いています。
ウィンドウの状態と属性
ウィンドウは、操作のいろいろな段階によって状態が変わります。またウィンドウの種類により多様な属性を内包しています。
- 最小化・最大化・通常状態
- ウィンドウには、最小化や最大化の機能があります。最小化すると、ウィンドウは消えアイコンの状態になります。アイコン状態では、コントロールメニューとタイトルしか表示しません。最大化するとスクリーン一杯に表示します。これらの状態から戻すと通常のウィンドウ状態になります。
- ウィンドウの可視性
- ウィンドウは、表示させたり(可視にしたり)表示させなかったり(不可視にしたり)できます。不可視ウィンドウは、描画しないことにより画面に表示しません。ウィンドウが可視の場合、ユーザーはそのウィンドウに入力して、ウィンドウの出力を見ることができます。ウィンドウが不可視の場合には、効果的には使用不能な状態になります。不可視ウィンドウは、Windowsやほかのウィンドウからのメッセージを処理することはできますが、ユーザーからの入力を処理することはできず、出力の表示も処理できません。アプリケーションはウィンドウの作成時にその可視性を設定します。また、作成後に可視状態を変更することもできます。
ウィンドウが可視状態であっても、ユーザーはそのウィンドウを画面上で見ることができない場合があります。たとえば、ほかのウィンドウがそのウィンドウの上に完全にオーバーラップしていたり、画面の端よりも外に出ていたりする場合があります。また、可視の子ウィンドウも、親子関係に基づいて確立されているクリッピングの規則の影響を受けます。親ウィンドウが可視でない場合は、その子ウィンドウもまた可視ではなくなります。
- アクティブと非アクティブ
- アクティブウィンドウとは、ユーザーが現在作業をしているアプリケーションのトップレベルウィンドウのことです。アクティブウィンドウであることをユーザーが容易に識別できるようにするため、Windowsはそのウィンドウをいちばん手前に表示させ、ウィンドウのタイトルバーと境界をシステム定義のアクティブウィンドウの色に変更します。アクティブウィンドウにできるのはトップレベルウィンドウだけです。ユーザが子ウィンドウで作業をしているときには、その子ウィンドウのトップレベルの親ウィンドウをアクティブ化します。
ある時点において、システム内でアクティブなトップレベルウィンドウは1つだけです。ユーザーはトップレベルウィンドウ(またはその子ウィンドウの1つ)をクリックするか、[Alt]+[Esc]キーか、[Alt]+[Tab]キーを押すことにより、ウィンドウをアクティブ化します。アプリケーションからは、SetActiveWindow関数を呼び出してトップレベルウィンドウをアクティブ化します。この関数のほか、SetWindowPosやDeferWindowPos、SetWindowPlacement、DestroyWindowなどの多くの関数により、種々のトップレベルウィンドウをWindowsにアクティブ化させることができます。
- フォーカスと使用不能のウィンドウ
- ウィンドウは使用不能にすることができます。使用不能にしたウィンドウは、キーボードやマウスからの入力を受け取りません。しかし、ほかのウィンドウやほかのアプリケーション、およびWindowsから送られるメッセージは、受け取ることができます。通常、アプリケーションは、ユーザーにウィンドウを使わせないようにするためにウィンドウを使用不能にします。たとえば、ダイアログボックス内のプッシュボタンを使用不能にすれば、ユーザーはそのボタンを押すことができなくなります。使用不能のウィンドウはいつでも使用可能に戻すことができ、再び通常の入力を受け取るようにすることができます。子ウィンドウが使用不能にされると、Windowsはその子ウィンドウのマウス入力メッセージを親ウィンドウに送ります。親ウィンドウはこのメッセージを使って、子ウィンドウを使用可能にするかどうかを決めます。
キーボード入力を受け取ることのできるウィンドウは、一度に1つだけです。キーボード入力を受け取ることのできるウィンドウは、キーボードフォーカスを持つ、といわれます。キーボードフォーカスを持つウィンドウをEnableWindow関数を使って使用不能にした場合、ウィンドウは使用不能になるばかりでなく、キーボードフォーカスをも失います。そして、EnableWindowはキーボードフォーカスをNULLに設定し、フォーカスを持つウィンドウがないことを示します。子ウィンドウやほかの子や孫ウィンドウがキーボードフォーカスを持っている場合は、その親ウィンドウが使用不能にされたときに、その子や孫ウィンドウはフォーカスを失います。
- 位置とサイズとZ順序
- Windows では、プロセスはそれぞれ複数の実行スレッドを持つことができ、それぞれのスレッドは複数のウィンドウを作成できます。ユーザーが現在作業をしているウィンドウを作成したスレッドはフォアグラウンドスレッドと呼ばれ、そのウィンドウは「前景ウィンドウ」と呼ばれます。また、これ以外のスレッドはバックグラウンドスレッドと呼ばれ、それらのスレッドが作成したウィンドウは「背景ウィンドウ」と呼ばれます。
各スレッドは、自分が占有するCPU時間の量を決定する優先順位レベルを持っています。スレッドの優先順位はアプリケーションが自分で設定することもできますが、通常はフォアグラウンドスレッドがバックグラウンドスレッドよりもわずかに高い優先順位レベルを持ちます。このため、フォアグラウンドスレッドはバックグラウンドスレッドよりも多くのCPU時間を占有します。フォアグラウンドスレッドは、標準の基本優先順位として優先順位9を持ちます。一方、バックグラウンドスレッドは、標準の基本優先順位として優先順位7を持ちます。
- ウィンドウの境界
- Windowsは、次の境界スタイルを提供します。
| スタイル |
説明 |
| WS_BORDER |
細い線の境界を持つウィンドウを作成します。 |
| WS_DLGFRAME |
二重の境界を持つウィンドウを作成します。通常、このスタイルはダイアログボックスに対して使われます。このスタイルを持つウィンドウにはタイトルバーを付けることはできません。 |
| WS_EX_DLGMODALFRAME |
二重の境界を持つウィンドウを作成します。WS_DLGFRAMEスタイルとは異なり、WS_CAPTIONスタイルを同時に指定してウィンドウにタイトルバーを付けることができます。 |
| WS_THICKFRAME |
サイズ変更境界を持つウィンドウを作成します。 |
ウィンドウの親子関係
ウィンドウは常に親子関係を持ちます。アプリケーションの最上位のウィンドウだけは、親がありません(NULLです)。親子関係は、WS_CHILDで子ウィンドウを作成する時点で親のウィンドウを指定することで成立します。
- 位置と動作
- Windowsは、子ウィンドウの位置を決めるときに、常に親ウィンドウのクライアント領域の左上隅からの相対座標を使います。親ウィンドウの境界の外には、子ウィンドウは表示されません。親ウィンドウよりもサイズの大きい子ウィンドウを作成したり、親ウィンドウの境界からその一部または全部がはみ出すように子ウィンドウの位置を設定したりした場合、Windowsは子ウィンドウをクリップします。つまり、親ウィンドウのクライアント領域の外側部分は表示されません。親ウィンドウに作用する動作は、次の表に示すように、子ウィンドウにも作用します。
| 親ウィンドウ |
子ウィンドウ |
| 破棄される時 |
親ウィンドウが破棄される前に自動的に破棄される。 |
| 非表示にされる時 |
親ウィンドウが非表示にされる前に非表示にされる。子ウィンドウは、親ウィンドウが可視のとき(表示されているとき)だけ、可視である(表示される)。 |
| 移動される時 |
親ウィンドウのクライアント領域内で移動される。移動後のクライアント領域の描画は子ウィンドウが行う。 |
| 表示される時 |
親ウィンドウが表示された後に、親よりも手前に表示される。 |
- 可視性
- 親ウィンドウが可視になると、その子ウィンドウもまた可視になります。同様に、親ウィンドウが不可視になると、その子ウィンドウもまた不可視になります。しかし、親ウィンドウがアイコン化されても子ウィンドウの可視状態は変わりません。つまり、子ウィンドは親ウィンドウといっしょにアイコン化されますが、WS_VISIBLEスタイルは変わらないということです。
- クリッピング
- Windowsは、親ウィンドウのクライアント領域から子ウィンドウを自動的にクリップするわけではありません。つまり、子ウィンドウと同じ位置の親ウィンドウの、部分に何らかの描画操作を実行した場合は、子ウィンドウの上に描画します。しかし、親ウィンドウが、WS_CLIPCHILDRENスタイルを持っている場合には、親ウィンドウのクライアント領域から子ウィンドウをクリップします。子ウィンドウがクリップされると、親ウィンドウはその上に描画できなくなります。
子ウィンドウは、同じクライアント領域内でほかの子ウィンドウの上にオーバーラップさせることができます。1つまたは複数のほかの子ウィンドウとともに同じ親ウィンドウを共有している子ウィンドウは、「兄弟ウィンドウ」と呼ばれます。兄弟ウィンドウは、それらのうちの1つが、WS_CLIPSIBLINGSスタイルを持っていないかぎり、互いのクライアント領域内で描画を行うことができます。子ウィンドウに対してこのスタイルを指定した場合は、その子ウィンドウとほかの兄弟ウィンドウとが重なる部分がクリップされます。
ウィンドウが、WS_CLIPCHILDRENまたはWS_CLIPSIBLINGSのどちらかのスタイルを持っている場合は、若干の実行性能の低下が起こります。子ウィンドウは各ウィンドウごとにシステムリソースを占有するため、アプリケーションでは不必要に子ウィンドウを使わないようにしてください。最適な実行性能を得るため、メインウィンドウを論理的に分割する必要のあるアプリケーションは、その操作を子ウィンドウを使って行わずに、メインウィンドウのウィンドウプロシージャで行うようにしてください。
- 親ウィンドウとの親子関係
- アプリケーションは、SetParent関数を呼び出すことにより、既存の子ウィンドウの親ウィンドウを変更できます。このとき、Windowsは、以前の親ウィンドウのクライアント領域からその子ウィンドウを削除し、新しい親ウィンドウのクライアント領域に移動させます。SetParentでNULLハンドルを指定した場合は、デスクトップウィンドウが新しい親ウィンドウになります。この場合には、子ウィンドウがデスクトップ上に描画され、デスクトップ上にあるほかのウィンドウの境界の外側に描画されます。GetParent関数は、子ウィンドウの親ウィンドウのハンドルを取得します。
親ウィンドウは、自分のクライアント領域部分を子ウィンドウに委ね、子ウィンドウはこの領域からすべての入力を受け取るようになります。ウィンドウクラスは、親ウィンドウのそれぞれの子ウィンドウについてすべて同じにする必要はありません。つまり、アプリケーションは、親ウィンドウの中に外観や動作の異なる複数の子ウィンドウを表示させることができるわけです。たとえば、ダイアログボックスには多くの種類のコントロールを含めることができますが、各コントロールはユーザーからさまざまな種類のデータを受け取ることのできる子ウィンドウです。
子ウィンドウは1つの親ウィンドウしか持つことができませんが、親ウィンドウは子ウィンドウをいくつでも持つことができ、それぞれの子ウィンドウがさらに子ウィンドウ(孫ウィンドウ)を持つことができます。このようにして連結されたウィンドウは、元の親ウィンドウの「子孫ウィンドウ」と呼ばれます。アプリケーションは、IsChild関数を使い、あるウィンドウが指定された親ウィンドウの子ウィンドウであるかまたは子孫ウィンドウであるかを調べることができます。EnumChildWindows関数は、親ウィンドウの子ウィンドウを列挙し、各子ウィンドウのハンドルをアプリケーション定義のコールバック関数に渡します。指定された親ウィンドウの子孫ウィンドウもまた列挙されます。
- メッセージ
- Windowsは、子ウィンドウの入力メッセージをその子ウィンドウに直接渡します。このため、親ウィンドウにはメッセージが渡されません。ただし、子ウィンドウが、EnableWindow関数によって使用不能にされている場合は例外です。この場合、Windowsは、子ウィンドウに渡されるはずだったすべての入力メッセージを親ウィンドウに代わりに渡します。これにより、親ウィンドウは入力メッセージを調べて、必要に応じて子ウィンドウを使用可能にすることが可能になります。
子ウィンドウは一意な整数IDを持つことができます。子ウィンドウIDは、コントロールウィンドウに対して作業を行うときに重要になります。アプリケーションはコントロールにメッセージを送ることによってその動作を指示しますが、このときにコントロールの子ウィンドウIDを使ってメッセージを直接送ります。また、コントロールはその親ウィンドウに通知メッセージを送りますが、通知メッセージにはコントロールの子ウィンドウIDが含まれており、親ウィンドウはこれを使ってメッセージを送ったコントロールを識別します。アプリケーションはほかの種類の子ウィンドウに対して、CreateWindowEx関数のhmenuパラメータにメニューハンドルではなく子ウィンドウのID値を設定します。
所有されているウィンドウ
オーバーラップウィンドウまたはポップアップウィンドウは、ほかのオーバーラップウィンドウまたはポップアップウィンドウから所有されることができます。所有されているウィンドウと子ウィンドウは違います。子ウィンドウは,WS_CHILD スタイルを持つウィンドウですが、所有されているウィンドウはそうとは限りません。所有されているウィンドウには、次のような制約があります。
- 所有されているウィンドウは、常にオーナーウィンドウよりも手前に表示される。
- Windowsは、オーナーウィンドウが破棄されるときに、所有されているウィンドウを自動的に破棄する。
- オーナーウィンドウがアイコン化されているとき、所有されているウィンドウは表示されない。
オーナーウィンドウになれるのは、オーバーラップウィンドウとポップアップウィンドウだけです。子ウィンドウはオーナーウィンドウにはなれません。アプリケーションは、WS_OVERLAPPEDスタイルまたはWS_POPUPスタイルを付けてウィンドウを作成するときに、CreateWindowEx関数のhwndParentパラメータとしてオーナーのウィンドウハンドルを指定することにより、所有されるウィンドウを作成できます。hwndParentパラメータには、オーバーラップウィンドウまたはポップアップウィンドウを識別しなければなりません。hwndParentパラメータが子ウィンドウを識別した場合は、Windowsはその子ウィンドウのトップレベルの親ウィンドウに、所有権を割り当てます。所有されているウィンドウを作成すると、アプリケーションはそのウィンドウの所有権をほかのウィンドウに移すことができなくなります。
ダイアログボックスおよびメッセージボックスは、デフォルトで所有されているウィンドウになります。アプリケーションは、ダイアログボックスやメッセージボックスを作成する関数を呼び出すときに、そのオーナーウィンドウを指定します。GW_OWNERフラグを指定してGetWindow関数を使えば、ウィンドウのオーナーのハンドルを取得できます。
|