目次へ    最終更新 : 2003/9/28

第7章 コントロール処理



 前章では、ウィンドウとダイアログを紹介した。これらトップレベル要素は、本章の主題であるコントロール(control)の集合を持つことができる。コントロールは、階層的であり得る、つまり、コントロールそれ自体から構成され得る。コントールを使用すれば、プログラムが一貫して構造化されたユーザーインターフェースを提供するのに役立つ。しかし、コントロールを使って動作する場合には多くの問題が関わってくる。

 まず最初に、セクション7.1では、各標準コントロールを紹介する。そして、セクション7.2では、より大きなコントロール構造を構築する為に、糊を紹介する。コントロールの重要な側面は、セクション7.3で示すそのレイアウトを管理することである。レイアウトに関連するのは、コントロールを有するウィンドウがリサイズされる場合に何が起きるべきかと言うことである。これをセクション7.4で議論する。最後に、セクション7.5は、コントロールの使用例を示す多くの例を含んでいる。


7.1 標準コントール

 オブジェクトI/Oライブラリコントロールの標準セットのデータ型定義は、モジュールStdControlDef(付録A.7)で示されている。これらは3つのグループに分割できる。

プラットフォーム標準コントロール

 これらは、全プラットフォームに存在し、プラットフォーム毎に定義された整合のルックアンドフィールを持つコントロールである。これらの要素をアプリケーションに加えると、プログラムは、経験あるユーザーが快適に感じる標準的なインターフェースを持つこととなる。



カスタマイズコントロール

 プラットフォーム標準コントロールを使用すればアプリケーションの使い易さが増大するが、追加的なルックアンドフィールを持つコントロールを生成しなければならない場合がある。この為、ライブラリは2つのカスタマイズコントロールを提供する。CustomButtonControlの外観はプログラム定義であるが、ライブラリは、それがボタンであるかのようにそのフィールを処理する。CustomControlは、プログラムがそのルックアンドフィールのあらゆる側面を定義したい場合に使用できる。

階層的コントロール

 コントロールを組み合せる単純な方法は、それを1つの階層的コントロールに配置することである。階層的コントロールは、常に新しいレイアウト通用範囲を導入する。この機能は、LayoutControlによって提供される。CompoundControlは、コントロール内のウィンドウに非常に類似している。つまり、スクロールバーを持つことができ、その背景にPictureを持つ等の点で類似している。

 コントロールは、以下の表で見ることができるように、広範囲にわたる属性の集合を持つ。階層的コントロールは、多くの特殊属性を持つ。これは、ウィンドウ属性とダイアログ属性に強く関連している。

汎用コントロール属性階層コントロール属性
ControlActivateControlHMargin
ControlDeactivateControlHScroll
ControlFunctionControlItemSpace
ControlHideControlLook
ControlIdControlOrigin
ControlKeyboardControlOuterSize
ControlMinimumSizeControlViewDomain
ControlModsFunctionControlViewSize
ControlMouseControlVMargin
ControlPenControlVScroll
ControlPos 
ControlResize 
ControlSelectState 
ControlTip 
ControlWidth 

 セクション7.1.11まで階層的コントロール属性の説明は措いておく。表の左列の属性を見てみよう。

ControlActivateとControlDeactivate

 ウィンドウとダイアログを持つあらゆる対話プログラムでは、ユーザー入力を受けるウィンドウ又はダイアログ、つまりアクティブウィンドウが1つ存在する。このウィンドウ又はダイアログがコントロールを持つ場合、ユーザー入力は更に、入力フォーカス(input focus)を持つ特定のコントロールに接続される。コントロールが入力フォーカスを持つ場合、そのControlActivate属性に関連付けられた関数が評価される。コントロールが入力フォーカスを緩める場合、ControlDeactivate属性関数に関して同一の事が起こる。

ControlFunctionとControlModsFunction

 これら2つの属性は、コントロールの最重要なコールバック関数属性である。ユーザーが関連する属性コントロールを選択するといつでも、第一の関数が評価される。ユーザーがコントロールを選択した時に押された修正キーも提供されることを除いては、第2の関数に付いても同様のことが起こる。これら2つの属性の両方ともが属性リストに現れる場合、その2つのうち最初の方が選択される。

ControlHide

 この属性は、コントロールが最初は不可視であることを定義する。これは、領域を占有する。デフォルトでは、コントロールは、ウィンドウ又はダイアログの要素である場合には可視的である。勿論、親オブジェクトが不可視である場合、全ての子コントロールも不可視である。

ControlId

 この属性は、それに関連するコントロールを定義する。Idを提供しない場合、(4章で説明するように)プログラムがコントロールを修正することはできない。

ControlKeyboardとControlMouse

 この属性は、関連するコントロールに、キーボード及びマウス処理コールバック関数を加える。大抵のプラットフォーム標準コントロールにおいては、これらの属性は無視される。というのも、プラットフォームは既に、その入力に対する応答を定義しているからである。

ControlMinimumSize

 この属性は、コントロールの最小サイズを定義する。この値は、リサイズの場合には関係ない(セクション7.4参照)。ControlMinimunSizeが提供されない場合、デフォルト値の0が選択される。

ControlPen

 設定される場合、この属性は、カスタマイズコントロールのルック関数が描画用に使用する初期ペン属性を定義する。ペン属性は、セクション5.1で紹介した。存在しない場合、デフォルトペン値が使用される。

ControlPos

 この属性は、関連するコントロールのレイアウト位置(セクション7.3参照)を決める。デフォルトでは、コントロールは前のコントロールのすぐ次に配置される(たまたま最初のコントロールである場合、左上端に位置設定される)。

ControlResize

 この属性は、コントロールがリサイズ可能であることを定義する。コントロールは、親オブジェクトに関するユーザー又はプログラムのリサイズ動作に応答する場合、リサイズ可能である。デフォルトでは、コントロールは、これらのイベントに関してリサイズしない。コントロールのリサイズ動作に付いては、セクション7.4参照。

ControlSelectState

 この属性は、コントロールがユーザー入力を受理する(Able)か否か(Unable)を定義する。大抵のプラットフォーム標準コントロールでは、ユーザーは、現在の選択状態に関する幾つかの視覚的な手掛りを得る。デフォルトでは、コントロールのSelectStateはAbleである。

ControlTip

 tip属性は、アプリケーション使用者に、プラットフォーム依存な方法で、コントロールの機能に関するテキストでの説明を提供する。この説明は、非常に簡単なものでなければならない(2、3語のみ)。

ControlWidth

 全てのプラットフォーム標準コントロールについて、その高さは、その要求される属性によって決められる。プログラムは、ControlWidth属性を設定することによって、このようなコントロールの幅に影響を与えることができる。この属性の引数は、以下の型定義を有する型ControlWidthの値である。

 本セクションの残り部分では、各標準コントロールを紹介する。まず、アルファベット順に非階層的コントロールを示し、階層的コントロールで終わる。各コントロールに関しては、定義するのに使用しなければならない型の集合を与える。一般的なコントロール属性の中でどれが有効であるかが指示される。この情報は、オブジェクトI/Oライブラリから取得することもできる。各コントロールの定義モジュールStdControlAttributeでは、どの属性が有効であるかを定義する述語関数がある。最後に、コントロール定義のシンプルな例を示す。

7.1.1 ButtonControl

 ボタンコントロール(button control)は、ウィンドウ又はダイアログの現在の状態が与えられると発生するはずの動作を表す。ボタンコントロールの定義は以下のようになる。

 ボタンコントロールは、文字列で与えられるタイトルを有する。文字列は、制御文字を有してはならない。というのも、一般的に、画面上にガラクタを作り出すからである。&文字は、ユーザーに、プラットフォームに依存したキーボードインターフェースを加えるのに使用できる。エスケープシーケンスは、&&である。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen 
ControlFunctionControlPos
ControlHideControlResize 
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth
ControlModsFunction  

 ボタンコントロールの初期サイズは、その最初のテキスト行とControlWidth属性によって決められる。ユーザーがボタンを選択すると、属性リストのControlFunctionとControlModsFunctionの最初のものが評価される。ボタンコントロールの名前が新しいテキスト行に修正される場合、そのサイズは変更されない。

 ボタンコントロールは、ウィンドウ又はダイアログの確認又はキャンセルボタンであってもよい(セクション6.2.1)。これは、ControlId属性リストを持っていなければならない。Id値はそれぞれ、WindowOkかWindowCancel属性に与えられなければならない。

 ここで示すのは、新規行を有するタイトルを持つButtonControlである。



7.1.2 CheckControl

 チェックコントロール(check control)は、任意数を選択できるチェックコントロール項目のグループである。全代替部は可視的である。チェックコントロールの定義は以下のようになる。

 RowsOrColumns引数は、項目の局所的なレイアウトを指示する。行毎のレイアウトは、Rows代替部によって示され、列毎のレイアウトは、Columns代替部によって示される。各チェック項目に関して、そのタイトル、幅、初期マーク状態とコールバック関数が指定される。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen 
ControlFunction ControlPos
ControlHideControlResize 
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth 
ControlModsFunction   

 チェックコントロール項目が選択される場合、そのマーク状態は切り替えられる(MarkからNoMarkへ、及びその逆)。他のどのチェックコントロール項目にも影響しない。そして、選択された項目に対応するコールバック関数が評価される。

 以下に示すのは、2列に配置される5つの項目からなるCheckControlの一例である。各奇数番の項目がチェックマークを持っている。



7.1.3 CustomButtonControl

 カスタムボタンコントロール(custom button control)は、ボタンコントロールのように感じられるが、その外観はプログラムによって改造されているコントロールである。カスタムボタンコントロールの定義は以下のようになる。

 カスタムボタンコントロールの初期サイズと外観の両方がプログラムによって定義される。カスタムボタンコントロールの外観は、セクション6.4.1で議論したように、ウィンドウの外観と同一である。UpdateState引数は、カスタムボタンコントロールそれ自体と同一サイズのzeroベースの矩形を持つ。あらゆるカスタムボタンコントロールは、外観描画関数に適用される*Picture環境を有する。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen
ControlFunctionControlPos
ControlHideControlResize
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSizeControlWidth 
ControlModsFunction  

 ユーザーがカスタムボタンコントロールを選択すると、属性リストのControlFunctionとControlModsFunctionの最初のものが評価される。

 ボタンコントロールは、ウィンドウ又はダイアログの確認又はキャンセルボタンでもあり得る(セクション6.2.1参照)。これは、ControlId属性集合を持っていなければならない。Id値はそれぞれ、WindowOk又はWindowCancel属性に与えられなければならない。

 CustomButtonControlの外観は、そのSelectStateに依存している。左側のピクチャは、カスタムボタンコントロールがAble状態にあることを示し、右側のピクチャは、Unable状態にあることを示している。



7.1.4 CustomControl

 カスタムコントロールは、ルックアンドフィールがプログラム定義であるコントロールである。カスタムコントロールの定義は以下のようになる。

 カスタムコントロールの初期サイズと外観の両方がプログラムによって定義される。カスタムコントロールの外観は、セクション6.4.1で議論しように、ウィンドウの外観と同一である。UpdateState引数は、カスタムコントロールそれ自体と同一サイズのzeroベースの矩形を持つ。あらゆるカスタムコントロールは、外観描画関数に適用される*Picture環境を有する。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivateControlMouse
ControlDeactivateControlPen
ControlFunction ControlPos
ControlHideControlResize
ControlIdControlSelectState
ControlKeyboardControlTip
ControlMinimumSizeControlWidth 
ControlModsFunction  

 カスタムコントロールのフィールは、そのマウス及びキーボードコールバック関数によって定義される。ユーザーがマウスを持つカスタムコントロールを選択する場合、マウスコールバック関数が全入力を処理する。カスタムコントロールが入力フォーカスを有し、ユーザーが打ち込む場合、キーボードコールバック関数がキーボード入力を処理する。

 このCustomControlの外観は、そのSelectStateに依存している。左のピクチャは、Able状態にあるカスタムコントロールを示し、右のピクチャはUnable状態にあるカスタムコントロールを図示している。



7.1.5 EditControl

 編集コントロール(edit control)は、ユーザーに、(典型的には少量の)テキストデータを編集するインターフェースを提供するのに使用される。編集コントロールの定義は以下のようになる。

 編集コントロールは、最初にテキスト行を表示する。テキスト行が新しい行を持っている場合、改行されると、その新しい行が解釈される。編集コントロールは、(ControlWidth引数によって定義される)初期内部幅を持ち、行の数(整数)を示す。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivateControlMouse 
ControlDeactivateControlPen 
ControlFunction ControlPos
ControlHideControlResize
ControlIdControlSelectState
ControlKeyboardControlTip
ControlMinimumSize ControlWidth 
ControlModsFunction   


 編集コントロールのSelectStateがUnableである場合、ユーザーは、テキストで打込むことはできない。プログラムは、ControlKeyboard属性を設定することによって、挿入したテキストをトレースし続けることができる。打込まれた各キーについて、そのキーボード関数が評価される。編集コントロールがControlId属性集合を有する場合、モジュールStdControlのgetControlText関数(付録A.4)を使用して、その内容を取得できる。

 ここにあるのは、内部幅が80ピクセルで、高さが3テキスト行であるEditControlの一例である。


7.1.6 PopUpControl

 ポップアップコントロール(pop up control)は、ただ一つの項目が選択されるポップアップコントロール項目のグループである。ポップアップコントロールの項目は、ポップアップメニューに示される。通常は現在選択されている項目だけが表示される。この為、ポップアップコントロールは、機能的に同等な(セクション7.1.7で議論する)ラジオコントロールよりも遥かに少ないメモリ消費量である。ポップアップコントロールの定義は以下のようになる。

 最初に選択した項目は、Index値によって指示される。規約として、オブジェクトI/Oライブラリでは、指示する場合、要素のインデックスは1から要素数までの範囲である。従って、n要素は、1...nによってインデックス化される。インデックスが範囲外である場合、つまり、1より小さいかnより大きい場合、インデックスはそれぞれ1とnに設定される。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivateControlMouse 
ControlDeactivateControlPen 
ControlFunction ControlPos
ControlHideControlResize 
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth
ControlModsFunction   


 ポップアップコントロール項目が選択される場合、前に選択された項目はチェックされず、新しい項目が選択された項目になる。そして、それに対応するコールバック関数が評価される。現在選択されている項目が選択される場合にも、そのコールバック関数が評価される。

 ここにあるのは、5つの項目からなるPopUpControlの一例である。最初の項目は、最初に選択される項目である。


7.1.7 RadioControl

 ラジオコントロール(radio control)は、ただ1つの項目が選択されるラジオコントロール項目のグループである。ラジオコントロールは、機能的にはポップアップコントロール(セクション7.1.6)と同等だが、より多くの領域を消費する。ラジオコントロールの定義は、チェックコントロール(セクション7.1.2)の定義とほとんど同一である。

 RowsOrColumns引数は、項目の局所レイアウトを指示する。列毎のレイアウトは、Rows代替部によって与えられ、行毎のレイアウトはColumns代替部によって与えられる。最初に選択された項目は、Index値によって指示される。オブジェクトI/Oライブラリの規約として、指示する際の要素のインデックスは、1から要素数までの範囲である。従って、n要素は、1...nによってインデックス化される。インデックスが範囲外である場合、つまり1より小さくnより大きい場合、それぞれ1とnに設定される。各ラジオ項目について、そのタイトル、幅とコールバック関数が指定される。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen 
ControlFunction ControlPos
ControlHideControlResize 
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth 
ControlModsFunction   


 ラジオコントロール項目が選択される場合、その前に選択されたラジオコントロール項目は非選択にされ、その新しいラジオコントロール項目に選択マークが付く。そして、それに対応するコールバック関数が評価される。このコールバック関数は、現在選択されている項目を選択した場合にも評価される。

 以下に示すのは、2列で配置され、5つの項目からなるRadioControlの一例である。最初は、第一の項目が選択されている。


7.1.8 SliderControl

 スライダコントロール(slider control)は、値の範囲内にある特定の値を選択するのに使用される。スライダコントロールの定義は以下のようになる。

 スライダコントロールには、水平方向(DirectionのHorizontal代替部)か垂直方向(DirectionのVertical代替部)を与えることができる。この方向については、このコントロールは、ControlWidth属性によって与えられる特定の長さを持つことができる。

 スライダコントロールの値の範囲は、SliderStateレコードによって定義される。初期スライダ状態が、その整数値の範囲を決める。つまり、sliderMinは最小値を与え、sliderMaxは最大値を与える。これらの値が間違った順序で与えられても適切な順序にされる。最初に選択された値は、sliderThumb値によって与えられる。この値は、sliderMinとsliderMaxの間になければならない。最小範囲より小さい値が与えられる場合、最小値に設定される。最大範囲より大きい値が与えられる場合、最大値に設定される。
 SliderControlの有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen 
ControlFunction ControlPos
ControlHideControlResize
ControlIdControlSelectState
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth 
ControlModsFunction   


 スライダコントロールは典型的には、ユーザーが選択できる5つの領域を持つ。これらの領域を図7.1に示す。

図7.1: SliderControlの領域

 ユーザーがスライダコントロールを使用する場合、そのコールバック関数が評価される。代数データ型SliderMoveは、スライダコントロールの各領域について代替構成子を有する。

 プログラムは、この情報で、何をすべきかを決めることができる。アプリケーションがユーザーの期待する方法で応答するかは、プログラマの責任である。

 ここに示すのは、水平方向で、200ピクセルの長さを持つSliderControlの一例である。これは、図7.1に示されたスライダコントロールをもたらす。

7.1.9 TextControl

 テキストコントロール(text control)は、ユーザーが変更できない1行のテキストを表示する。テキストコントロールの定義は以下のようになる。

 有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlMouse 
ControlDeactivate ControlPen 
ControlFunction ControlPos
ControlHideControlResize 
ControlIdControlSelectState 
ControlKeyboard ControlTip
ControlMinimumSize ControlWidth
ControlModsFunction   


 テキストコントロールの初期サイズは、その初期テキスト行とそのControlWidth属性によって決められる。テキストコントロールは、リサイズできず、プログラムがテキスト行を修正した場合にもサイズが変わらない。

 ここに示すのは、テキストコントロールの一例である。


7.1.10 LayoutControl

 レイアウトコントロール(layout control)は、他のコントロールを持つコントロールである。これは、新しいレイアウト通用範囲(layout scope)を導入する。つまり、その内側のコントロールは、レイアウトコントロールの境界に関連して配置される。レイアウトコントロールの定義は以下のようなものである。

 型定義から理解できるように、型変数cが型構成子の位置に現れる。Controls型構成子クラスのLayoutControlのインスタンス宣言は、cがControlsインスタンスそれ自体でなければならないという制限を加える。有効なコントロール属性は以下のものである。

コントロール属性有効コントロール属性有効
ControlActivate ControlOrigin 
ControlDeactivate ControlOuterSize
ControlFunction ControlPen 
ControlHideControlPos
ControlHMarginControlResize
ControlHScroll ControlSelectState
ControlIdControlTip 
ControlItemSpaceControlViewDomain 
ControlKeyboard ControlViewSize
ControlLook ControlVMargin
ControlMinimumSizeControlVScroll 
ControlModsFunction ControlWidth 
ControlMouse   


 ControlOuterSize又はControlViewSize属性として提供されない場合、レイアウトコントロールのサイズについては、システムがそのコントロール要素から導出する(コントロールのレイアウトに関する更なる情報に付いてはセクション7.3参照)。多くの属性がそのサイズと要素レイアウトに関連している。ControlMinimumSize属性は、レイアウトコントロールの最小サイズを決め(コントロールのリサイズ参照、セクション7.4)、ControlResize属性は、そのリサイズ動作を制御し(セクション7.4も参照)、ControlItemSpace、ControlHMarginとControlVMargin属性はそれぞれ、要素間の距離と、レイアウトコントロールの境界に対する水平及び垂直の距離を定義する。レイアウトコントロールがこれらの属性のどれも指定していない場合、その親オブジェクトと同一の属性値を得る。

7.1.11 CompoundControl

 合成コントロール(compound control)は、他のコントロールを持つコントロールである。これは、新しいレイアウト通用範囲(layout scope)を導入する(セクション7.1.10のLayoutControl参照)。合成コントロールの型定義は、LayoutControlの型定義とほとんど同一である。

 型定義が同等であるにもかかわらず、合成コントロールは、プログラマに、同類のレイアウトコントロールよりも遥かに多い機能を提供する。このことは、その有効なコントロール属性を見れば明らかになる。

コントロール属性有効コントロール属性有効
ControlActivateControlOrigin
ControlDeactivateControlOuterSize
ControlFunction ControlPen
ControlHideControlPos
ControlHMarginControlResize
ControlHScrollControlSelectState
ControlIdControlTip
ControlItemSpaceControlViewDomain
ControlKeyboardControlViewSize
ControlLookControlVMargin
ControlMinimumSizeControlVScroll
ControlModsFunction ControlWidth 
ControlMouse  


 ControlOuterSizeかControlViewSizeとして提供されない場合、合成コントロールのサイズについては、システムがそのコントロール要素から導出する(コントロールのレイアウトに付いての更なる情報に付いてはセクション7.3参照)。多くの属性がそのサイズと要素レイアウトに関連している。ControlMinimumSize属性は、合成コントロールの最小値を決め(コントロールのリサイズ参照、セクション7.4)、ControlResize属性は、リサイズ動作を制御し(セクション7.4も参照)、ControlItemSpace、ControlHMarginとControlVMargin属性はそれぞれ、要素間の距離と合成コントロールの境界に対する要素の水平及び垂直の距離を定義する。合成コントロールがこれらの属性のどれも指定しない場合、その親オブジェクトと同一の属性値を得る。

 合成コントロールの構造は、ウィンドウの構造と同一である(セクション6.1.1)。これは、そのトップ層をウィンドウフレームではなく合成フレーム(compound frame)と呼ぶことを除いて、ウィンドウと同じく3つの層からなる。合成フレームは、リサイズコントロール等のようなタイトルも特徴も持たない。

 ウィンドウに似て、合成コントロールはビュー領域を有する。セクション6.1.1で説明したように、ビュー領域は、描くことのできる有限領域を定義し(5章)、コントロールを配置する領域としても使用できる(セクション7.3)。合成コントロールには、スクロール属性、つまりControlHScrollとControlVScrollも加えることができる。これらの属性は、現在の合成コントロールのビューフレームの嗜好を制御する。現在可視的なビューフレームの左上端は、原点(origin)と呼ばれる。この値は、最初はControlOrigin属性によって設定できる。ControlLook属性は、オブジェクトI/Oライブラリによって使用され、ウィンドウについてと全く同じ方法で、合成コントロールの文書層を描画する。

 合成コントロールのフィールは勿論、その要素コントロールによって部分的に決められる。ControlMouse(ControlKeyboard)属性が与えられる場合、合成コントロールは、それに接続されている全てのマウス(キーボード)イベントを処理できる。


7.2 コントロールの糊

 前セクションでは、コントロールの標準セットを議論した。このリストは、全てのコントロールクラスインスタンスをカバーしてはいない。ライブラリモジュールStdControlClass(付録A.6)では、多くの追加的なインスタンス、つまり、型構成子:+:、ListLS、NilLSとAddLS、NewLS(これらの定義はモジュールStdIOBasic、付録A.13で見つけることができる)が定義されている。これらの追加的なインスタンスは、コントロールを糊付けする(glue)のに必要である。これらを以下で取り扱う。


7.2.1 :+:

 コントロールを糊付けする最も一般的な構成子は、:+:である。その型構成子定義とControlsクラスインスタンス宣言は以下のようなものである。

 同一の型lsの局所状態と型csの文脈状態に作用する、2つのControlsインスタンスc1とc2を持つものとする。ここで、糊付けされた式c1:+:c2も、同一の局所状態と文脈状態に作用するControlsインスタンスである。:+:は右結合であるので、式c1:+:c2:+:c3は、c1:+:(c2:+:c3)と読むことになる。

 一例として、セクション7.1.1のボタンコントロール定義buttoncontrolとセクション7.1.5の編集コントロール定義editcontrolを再考する。

 ここで、式(buttoncontrol :+: editcontrol)と(editcontrol :+: buttoncontrol)は合法な組合せである。

7.2.2 ListLSとNilLS

 :+:型構成子が常に最適な糊という訳ではない。同型のコントロールの集合を構成する場合、リストとリストの内包表記を使用する方が遥かに便利である。未知数のコントロールを構成する場合、:+:を使用するのは不可能でさえある。ここでも、リストの方が柔軟性を提供する。リストライクな糊は、型構成子ListLSによって提供される。型構成子NilLSは、ListLS []の速記である。これらについては、階層的なコントロール、ウィンドウ又はダイアログがコントロールを持たないことを述べるのに使用できることも便利である。

 同一の型lsの局所状態と文脈状態csに作用する、Controlsインスタンスのリストであるxs = [c1...cn]が与えられると、式ListLS xsも、同一の局所状態と文脈状態に作用するControlsインスタンスである。

 一例として、テキストラベルのリストlabelsを持っており、以下の方法でコントロールの集合を生成したいものとする。つまり、labelsの各ラベルについて、ラベルのついた内容を持つテキストコントロール、そのテキストコントロールの右には、100ピクセルの幅を有する空の編集コントロールを生成する。編集コントロールは、同一のx軸に配置されなければならない。この方法は、あらゆるリストの長さに対しても動作し、勿論、様々な長さのラベルを処理できなければならない。1つ追加される危険な性質は、テキストコントロールと編集コントロールが異なった高さを持つ恐れがあるということである(プラットフォーム依存)。

 ここでは、その方法を示す。まず、最長のラベルサイズを決める。

 この値が与えられると、labelsから最長のラベルを選択する。

 ここで、ListLSを使用すれば、リストの内包表記を使用して編集コントロールに糊付けされた任意数のテキストコントロールを生成できる。

 labelsの以下の値に適用され、それをダイアログに入れると、

 この結果は図7.2で示されるようになる。

図7.2: リストの内包表記による糊付け

7.2.3 AddLSとNewLS

 前に議論した糊付け型構成子は常に、同一の局所状態と文脈状態に作用するコントロールを糊付けする。他の2つの糊付け構成子AddLSとNewLSは、局所状態を拡張、変更するのに定義される。

 型lsの局所状態と型csの文脈状態に作用するControlsインスタンスc1が与えられると、型(new,ls)の拡張局所状態と、型csの同一の文脈状態に作用する別のControlsインスタンスc2を加えることができる。xを型newの値であるとすると、これは、式c1 :+: {addLS=x,addDef=c2}によって行われる。

 型lsの局所状態と型csの文脈状態に作用するControlsインスタンスc1が与えられると、型newの新規局所状態と、型csの同一の文脈状態に作用する別のControlsインスタンスc2を加えることができる。xが型newの値であるとすると、これは、式c1 :+: {newLS=x,newDef=c2}によって行われる。

 両方の場合とも、局所状態の拡張部分と新規局所状態は、存在量化を使用して、外部の文脈から完全にカプセル化される。

 この方法によるコントロールの糊付ける一例として、手動で増加可能なカウンタコントロールを実装してみよう。これを行う為、LayoutControlを他の3つのコントロールで満たす。現在のカウント値を表示する為に、Unable EditControlが使用される。2つのButtonControlsは、カウンタを増減するのに使用される。

 図7.3は、カウンタ値-15になるようユーザーが操作した後のカウンタを表示している。

図7.3: カウンタコントロール


7.3 コントロールレイアウト

 オブジェクトI/Oライブラリは、プログラマに、コントロールのレイアウトを定義する表現豊かなレイアウト機構を提供している。以前に見たように、コントロールは、ウィンドウ、ダイアログ、レイアウトと合成コントロールの要素であってもよい。本セクションで議論するレイアウト規則は、これらの各場合に適用される。レイアウト規則の中には、親オブジェクトのビュー領域とビューフレームを参照するものもある。ダイアログとレイアウトコントロールの場合、これら2つは同一である。つまり、これらは、親オブジェクトの内部サイズと等しいサイズを持つ、zeroベースの矩形である。

 見てきたように、あらゆるコントロールは、ControlPos属性を持つことができる。この属性は以下のように定義される。

 コントロールのレイアウト位置は、2つの値、つまりItemLoc値とItemOffset値からなる。ItemLocは実際には、コントロールの位置を決め、ItemOffset値は、この位置にオフセットを加える(勿論これは、他のコントロールの位置に影響する)。ItemLoc値は、4つのグループに分けることができる。
 関連位置レイアウトを持つコントロールは、レイアウトルートコントロールを1つ持つレイアウト木(layout tree)を形成する。レイアウトルートコントロールのレイアウト属性は、レイアウト木全体のレイアウト位置を決める。それが固定位置にある場合、レイアウト木は固定位置を取得する。境界揃えの場合、レイアウト木は、同一境界に配置される。行揃えの場合、レイアウト木は行揃えになる。

 最初のレイアウトルートコントロールを除いて、コントロールのデフォルトレイアウト属性は、(RightToPrev,zero)である。最初のレイアウトルートコントロールについては、そのデフォルト属性は、(Left,zero)である。従って、デフォルトレイアウト順序は、単線上に左から右に向かう。

 コントロールは、部分的又は完全に重複することが認められている。これは、どんな時でもたった1つのコントロールだけが可視的である場合に、不可視的コントロールと可視的コントロールを組み合せる場合に特に有用である。これによって、コントロールを隠したり表示したりすることによって、容易な方法で、プログラムがコントロール構造を変更できるようになる。

 本セクションの残りの部分では、コントロールレイアウトを例解する為、多くの例を示す。各例では、レイアウトされるコントロールが、図7.4に示されるようなビュー領域とビューフレームを持つ親オブジェクトに配置されるものとする。x軸(水平矢印)とy軸(垂直矢印)は、座標zeroで交差する。

図7.4: ビュー領域とビューフレーム


図7.5: 5つのコントロールのレイアウト木


 コントロールは、箱として表示されている。図7.5は、例で使用されるコントロールの配列を示す。これは、5等分されたコントロールc0...c4からなる。レイアウトルートコントロールはc0である。コントロールc1..c4は各々、レイアウト属性LeftOf、RightTo、AboveとBelowによって、c0に関連するレイアウトを持つ。オフセットはzeroである。
                                        

7.3.1 固定位置でのレイアウト

 コントロールとFixレイアウト属性を有するレイアウト木は、親オブジェクトのビュー領域に関連して配置されている。従って、その可視性は、親ビューフレームの現在の嗜好に依存している(ビューフレームが外側にある全てをクリップすることを思い出して欲しい)。図7.6は、レイアウトルートコントロールが属性(Fix,zero)を有する場合の図7.5のコントロール配列を図示している。

図7.6: (Fix,zero)でのレイアウト木

7.3.2 ビューフレーム境界でのレイアウト

 境界揃え位置にコントロールを配置すると、コントロールが常に可視的であることが保証される。というのも、(ビューフレームが十分大きいならば、)その位置は、親オブジェクトのビューフレームに関連しているからである。このコントロールがレイアウトルートである場合、そのレイアウト木のコントロールの可視性は、その関連位置に依存する。例えば、レイアウトルートコントロールが(LeftTopを使用して)ビューフレームの左上に配置される場合、全てのコントロールがzeroオフセットであるとすると、その左及び上に関連配置されるコントロールは不可視である。

図7.7: LeftTop、RightTop、LeftBottomとRightBottomでのレイアウト木


 これは図7.7で例解される。図7.7は、zeroオフセットで、LeftTop、RightTop、LeftBottomとRightBottomを使用してビューフレームのあらゆる角に位置設定される場合の図7.5のコントロール配列の位置を図示している。

7.3.3 行内のレイアウト

 行内にコントロールとレイアウト木をレイアウトすることは、英語のテキスト片に文字を書込むことに似ている。つまり、次コントロールは各々、新行が開始されるまで全コントロールのちょうど次に配置される。新行は、前行の下から始まる。行は、揃え、中央揃え又は揃えにすることができる。レイアウト属性Left、CenterとRightは、新行とその配置を導入する。最初の行は、ビューフレームの頂上から始まる。ビューフレームが全行を把握するに十分な大きさでない場合、これらの行のコントロールは可視的ではないだろう。

図7.8: Left、CenterとRightでのレイアウト木


 これは、図7.8で例解される。図7.8は、zeroオフセットを使用して、Left、CenterとRightにそれぞれ配置される場合の図7.5のコントロール配列の位置を図示する。

7.3.4 レイアウトオフセット

 今まで、レイアウト属性の例において、zeroオフセットを使用してきた。コントロールのレイアウト位置は、以下のように、オフセットベクタ値v = {vx,vy}によって変更される。まず、コントロールのレイアウト位置は、上で説明したように、zeroオフセットを使用して計算される。ここで、このことがちょうど位置pos = {x,y}をもたらすものとする。すると、コントロールの実位置は、{x=x+vx,y=y+vy}である。図7.9はこれを例解する。2つのコントロールc0とc1が与えられると、図7.9は、オフセット値v = {vx,vy}を持つRightToコントロールc0にc1を配置する結果を図示する。ダッシュボックスは、zeroオフセットを使用して、c1の位置を図示する。

図7.9: オフセットベクタを使用してコントロールをレイアウトする


7.3.5 前コントロールに関連するレイアウト

 本セクションで前に説明したように、コントロールのデフォルトレイアウト属性は、(RightToPrev,zero)である。前コントロールを参照するその他のレイアウト属性は、LeftOfPrev、AbovePrevとBelowPrevである。本セクションでは、前コントロールが何かを説明する。

 セクション7.2では、コントロール構造を生成する糊を導入した。このようなコントロール構造を見る最善の方法は、それの番号付けされたグラフ構造を見ることである。セクション7.1で導入したように、a、bとcの標準Controlsクラスインスタンスを持つ以下の式(a:+:b:+:c)を考える。図7.10は、そのグラフ構造を図示している(:+:が右結合であることを思い出して欲しい)。

図7.10: (a:+:b:+:c)の番号付けされたグラフ


 グラフの各ノードはインデックスを持つ。ノードが糊ノードである場合、最初の番号は、左部分木、その次は、そのノード自体、その次は、右部分木である。ノードが標準Controlsクラスインスタンスである場合、それに番号を付ける。CompoundControlの部分木のノードには番号を付けない。このように進むと、図7.10の各ノードのインデックス値を得る。インデックスiのグラフノードが標準Controlsクラスインスタンスの1つを表示する場合、その前のコントロールは、iより少ない最大インデックスを持つグラフノードによって表され、標準Controlsクラスインスタンスの1つも表示する。従って、cの前コントロールは:+:4ではなくb3である。というのも、bは標準Controlsクラスのインスタンスであると想定していたからである。同様に、bの前要素は、2つの:+:ノードのどちらでもなくa1である。最後に、aは前コントロールを持たない。


7.4 コントロールのリサイズ

 オブジェクトI/Oシステムは、親オブジェクトの動作をリサイズする為に、コントロールが応答するシンプルな機構を持っている。コントロールがイベントをリサイズするべく応答したい場合、それはControlResize属性を持つはずである。これは、以下のように定義される。

 コントロールリサイズ関数は、関連コントロールの現在の外サイズ(outer size)、親オブジェクトの旧ビューフレームサイズと親オブジェクトの新規ビューフレームサイズに適用される。その結果のサイズは、その新規外サイズとされる。この計算は、リサイズされているオブジェクトの部分であるコントロールの全てに関して実行される。階層コントロールがリサイズ関数を持ち、その新サイズが旧サイズと異なっている場合、この計算は再帰的に継続し、そうでなければ、要素のレイアウトは再計算されない。コントロールの新サイズが与えられると、レイアウトはそれに従って再計算され調節される。この戦略の効果は、コントロールの関連レイアウトが決して変更されないということである。

 一例として、ビューフレームのトップで互いに隣接する3つのCustomControlsを常に表示するCompoundControlを持つことを考える。CompoundControlは、そのビューフレーム幅が、その持つControlsResize関数compoundresizeを使用して、常に3で割り切れることに注意する。そのControlLook関数は、その現在のビューフレームに合わせる矩形を描画する。

 CustomControlsは、ControlResize関数customresizeを使用して、親コントロールの新しい幅に従って、その幅をリサイズする。そのルック関数に付いては、セクション6.4.1の57ページ(訳者注:原書)で述べたルック関数を再利用する。この関数は、現在のビューフレームと2つの対角線を調節する矩形を描画する。

図7.11: 3つのCustomControlsを持つCompoundControlのリサイズ


 図7.11は、親オブジェクトがリサイズされる場合にコントロールに何が起こるのかを示している。左には、CompoundControlとそのCustomControlの初期状態が表示される。セクション7.3で説明したように、3つのカスタムコントロールは、レイアウト属性(Left,zero)とその他のCustomControls (RightToPrev,zero)を持つレイアウトルートコントロールをもつレイアウト木を形成する。中央では、CompoundControlが右下にリサイズされる。このリサイズの動作は、compoundresizeを使用したCompoundControlのサイズの最初の再計算をもたらす。この値は旧サイズとは異なっているので、各CustomControlについて再計算が継続する。最終結果は右に表示される。


7.5 例

 ここでは、コントロールを使用した追加的な例を多く示す。前章で既に取り扱ったキースポッティング例とマウススポッティング例を再訪する。

7.5.1 キースポッティング再訪

 本例では、セクション6.7.1のキースポッティング例に、コントロールのキーボード入力も監視する機能を拡張する。1つのCustomControlを持つ1つのCompoundControlを持つウィンドウを生成する。以下で各部品を議論する前に、それらがキーボード入力を処理する方法を見ておく。プログラムのスクリーンショットを図7.12にしめす。

図7.12: 動作中のキースポッティングプログラム


 各部品は、キーボードセンシティブであり、同一のKeyboardFunctionのspottingを使用する。この関数は、セクション6.7.1で示されるものとほとんど同じである。唯一の違いは、キーボード入力がウィンドウの代わりにCustomControlに表示されているということである。この為、spottingは、CustomControlのIdを引数に持つ。また、現在入力フォーカスを持つのが誰かを述べる文字列をも引数に持つ。ここで、spottingは、(True論理値を使用することによって)CustomControlのLook関数を変更し、その更新を強制する。

 CustomControlのLook関数であるlookは、元のルック関数とほとんど同じである。それが、その引数文字列を中央に配置し、その回りに矩形も描画するので、部品がどこにあるのかを容易に分かるということを除いて。

 CustomControlであるcustomは、キーボードが何を入力したのかをどの部品が現在受けているのかを表示する。そのコントロールはcidによって特定される。これは、KeyboardFunctionであるspottingに、Idと文字列"Control"の引数を持たせている。その初期の外観は、それ自体の周りに箱を描く。コントロールはリサイズ可能で、ControlResize属性を加えることによって指定される。親オブジェクトがリサイズされるといつでも、customは全く同じ量だけそのサイズを変更する。

 CompoundControlであるcompoundは、customしか持たない。そのKeyboardFunctionであるspottingは、customのIdと文字列"Compound"を引数に持つ。その初期ビューフレームサイズは、customを完全に表示するのに十分大きくなるように選択される。これは、それ自体の周りに箱を描画するのにlook関数を便利に使用する。合成コントロールもリサイズ可能で、customと同じリサイズ関数を使用する。

 最後に、Windowであるwindowは、compoundしか持たない。そのspotting関数は、customのIdと文字列"Window"を引数に持つ。その初期ビューフレームサイズは、compoundを完全に表示するに十分大きくなるように選択される。この為にも、余白属性が設定される。プログラムの停止は、ユーザーがウィンドウを閉じる場合にプログラムを終了させることによって処理される。

 定義しなければならないが、未だ残っている詳細は、対話プログラムとウィンドウの実際の生成である。完全にする為、以下にkeyspottingのプログラムコードを示す。

7.5.2 マウススポッティング再訪

 本例では、セクション6.7.2のマウススポッティング例を拡張する。全く同じように、改訂版マウススポッティング例は、上で議論した改訂版スポッティング例とほとんど同じである。唯一の違いは、ウィンドウのタイトルと、キーボード属性とマウス属性を置き換えていることである。プログラムのスクリーンショットを図7.12で示す。完全にする為、以下に改訂版マウススポッティング例のコードを示す。

図7.13: 動作中のマウススポッティングプログラム



First Uploaded : September 18, 2003
Last Modified : September 28, 2003

Back