「チェックボックスとラジオボタン」
では、ボタンとテキストフィールド以外のコントロールについて、主な使い方を見ていきましょう。まずはチェックボックスからです。——チェックボックスは、Interface
Builderのパレットで、前回まで使った(普通の)NSButtonの下にあります。これをドラッグ&ドロップすれば、それだけでチェックボックスが利用できるようになります。ON/OFFを制御するようなコードを用意する必要はありません。
実際に作成して、Infoウィンドウでアトリビュートを確認するとわかることですが、チェックボックスも、実は前回使ったプッシュボタンと同じ「NSButton」という部品なのです。違いは1つ、Typeが「Push
Button」か、「Check Box」か、ということだけです。Interface Builderのパレットは、このように「同じ部品のアトリビュートを変更したもの」がいくつか並べられていたりします。普通の感覚では「1つ1つの部品はすべて異なる種類のものだ」と考えがちですが、そうではないのですね。
さて、このチェックボックスは、マウスでクリックしてON/OFFするものです。ON/OFFの状態は、Infoウィンドウにある「Selected」というアトリビュートで設定できます。これがONになっていれば、チェックがONの状態となるわけです。
では、スクリプト内からチェック状態を調べるにはどうすればいいか。これは少し注意が必要です。注意その1は「チェック状態は、selectedという属性ではない」ということ。どうも私たちは「アトリビュート=属性」と考えてしまうところがあり、「アトリビュートがSelectedなら属性もselectedだろう」と思ってしまいますが、そうではないのです。NSButtonの選択状態を示す属性は「state」というものです。間違えないように。
そして注意その2は、「stateの値は整数である」ということです。ON/OFFの値なんだから、真偽値(boolean)だろうと漠然と考えてしまいがちですが、stateは「二者択一の値」ではありません。実は「三者択一」なのです。それは、以下のようになります。
- 値:0 OFFの状態
- 値:1 ONの状態
- 値:-1 ミックス状態
最後の「ミックス状態」というのは、「階層を持つチェックボックス」で用いられます。インストーラなどによく見かけるもので、チェックボックスの中に、更に細かな状態を示す複数のチェックボックスが組み込まれているような場合、「内部のいくつかがONになっている(つまりONとOFFが混じってる)状態」として、チェック部分に−記号が表示されることがあります。これがミックス状態です。
チェックボックスをクリックした際に処理を行なわせるには、「clicked」イベントを使います。チェックボックスも、普通のプッシュボタンと同じNSButtonなのですから、クリックしたときの処理方法も普通のボタンとまったく同じです。
では、これらを使って「クリックしたらチェックボックスの状態をテキストフィールドに表示する」というようなサンプルを考えてみましょう。ここでは、チェックボックスの名前を「check1」、書き出すテキストフィールドの名前を「text1」、これらがあるウィンドウの名前を「win1」としてスクリプトを考えてみます。
on clicked theObject |
ざっとこんな感じになるでしょうか。まず、ifで「name of theObject」を調べ、これが「check1」だったら処理を行なうようにしてあります。複数のコントロールでclickedが使われるようなときは、このようにしてコントロールをチェックして処理をするのでしたね。
ifの中では、まず「state of theObject」でイベントが発生したコントロールのstateを調べています。このように、パラメータのtheObjectを「button
"check1" of window "win1"」と同じ感覚で利用できるのでした。このほうが楽チンですね。
そして、stateの値に応じてテキストを変数ansにおさめ、最後にそれをテキストフィールドの「contents」に設定しています。——あれ? テキストの値は「string
value」じゃ?? と思った人。その通りなんですが、特に「○○の値として取り出す」ということでなく、一般的な「納めてある値」を示す場合には、contentsというものが使えます。ここでは「テキストフィールドに値をおさめる」わけですから、既におさめてある値が厳密にどんな種類のものかなんて知る必要はありません。それでcontensを使っているわけです。
まぁ、別に「どういうときにcontentsを使い、どういうときにstring valueを使うか」なんてルールがあるわけじゃありません。その場その場で使いやすいものを使えばいいでしょう。
さて、チェックボックスときたら、次はやっぱりラジオボタンでしょう。が、こいつは実はちょっとややこしいのです。なぜなら、ラジオボタンは普通のNSButtonではなく、別の部品になるからです。それは「マトリックス(NSMatrix)」というものです。
ボタンというのは基本的にみんなNSButtonで、そのTypeが違うだけだ、ということがわかってきました。が、NSButtonを配置してTypeを「Radio
Button」に変更してもラジオボタンは作れません。表示は確かにラジオボタンになるのですが、「複数の項目から1つを選択する」という機能は組み込まれないのです。ラジオボタンとしての機能を持たせるためには、「複数のコントロールを1つのものとして扱う」ということができないといけません。
まさに、そのためにあるのが「マトリックス」です。マトリックスとは複数のコントロールをまとめて扱うための専用の部品です。Interface
Builderのパレットには、標準で複数のボタンを組み込んだマトリックスが用意されています(チェックボックスの下にある「Radio」というボタンが2つ縦に並んでいるやつです)。これを配置すると、初期状態ではボタンが2つあるマトリックスが作成されます。
Infoウィンドウを見ると、「NSMatrix」という部品の細かなアトリビュートが表示されます。とりあえず、デフォルとのままで大丈夫でしょう。覚えておきたい主なものをまとめると以下のようになります。
- Background Color——背景の色。「Draws background」をONにすると表示。
- Mode——動作モード。各部品の選択されるルールみたいなもの。
- Allows empty selection——無選択を許可するか。
- Spacing——各部品の縦横の間隔。
- Row/Col——縦横に並べる部品の数。
ただ1つ注意しておきたいのは「Mode」です。これが「Radio」になっていないと、ラジオボタンのように「クリックした1つだけがONになる」という動きになりません。
また、マトリックスに表示される部品の数は「Row/Col」という右下のフィールドに数字を書き込んで変更できます。あるいは、オプションキーを押しながら、配置したマトリックスの角部分をマウスでドラッグし大きさ変更すると、大きさに合わせて表示されるコントロールの数が自動的に増減します。
また、「中に組み込まれているボタンのアトリビュートはどう設定するんだ?」と思う人もいるでしょうが、これは、マトリックスを選択し、その中にあるボタンを更にダブルクリックすると、そのボタンの設定がInfoウィンドウに表示されます。つまり、マトリックスは二重構造になっているのです。普通に選択するとマトリックス全体が選択され、更にダブルクリックすると内部の部品が選択される、というわけです。
実際にマトリックスを使ってみると、ちょっとおかしなことに気づきます。それは「中にあるボタンはNSButtonのはずなのに、NSButtonCellと部品名が表示される」ということです。——先ほど「複数のボタンを組み込んだマトリックス」といいましたが、実はこれは正確ではありません。正しくは「複数のボタンセルを組み込んだマトリックス」というべきなのです。
Cocoaのコントロールは、実はいくつかの部品が組み合わせられて1つの部品を構築しているのです。それは大きく分けて「モデル」「ビュー」「コントロール」の3つです。このことから、Cocoaの部品のような方式を「MVC(Model-View-Control)」といったりします。3つの要素は、それぞれ以下のような働きをします。
- モデル——部品の構造部分。
- ビュー——部品の表示部分。
- コントロール——部品の制御部分。
——まぁ、いきなりこんなふうにいわれてもよくわかんないですよね。別に、上の3つがどういうものかなんて、今の段階ではまったく理解する必要などありません。要するに「内部的な部分と、外見の部分が、Cocoaの部品では分かれているんだ」ということだけ知っていれば十分でしょう。
この内の「外見の表示」に関する処理を行なっているのが「セル」と呼ばれるものです。例えばボタンの場合には、ボタンのモデルとなるNSButtonに、「NSButtonCell」というビュー部分が組み込まれている、と考えられるわけですね。
マトリックスに組み込まれているのは、この「ボタンセル(NSButtonCell)」部分なのです。セルは、表示に関する機能を一通りと、「アクション」というごく単純なイベントを1つだけもっています。本来NSButtonに用意されている他の細かなイベントなどは何もありません。が、それで十分なんです、マトリックスは。そうでしょう?
NSButtonCellのアトリビュートを見ればわかるように、表示に関する限り、ボタンに必要なものはすべてそろっています。ボタンはそれなりに複雑なプログラムですが、ボタンセルは「表示部分だけ」ですから、ボタンに比べるとプログラムもシンプルでメモリも食わず処理もシンプルです。マトリックスのようにたくさんの部品を扱う場合、セルの方が便利なのですね。
まぁ、あんまり「ボタンとボタンセル」の違いなどについて細々と理解する必要はありません。ここでは「マトリックスの中身は、ボタンではなくボタンセルだ」ということだけ頭の片隅にいれておけば十分でしょう。
さて、それではマトリックスをスクリプトで操作する上で必要な事柄も頭に入れておきましょう。マトリックスには、ボタンと同様に「clicked」イベントが用意されています。また、これとは別に、内部に組み込まれている1つ1つのボタンにも「clicked」イベントがあります。
従って、組み込まれた全ボタンのclickedイベントをONにして、1つ1つのボタンごとに処理を用意すれば、各ボタンをクリックした際の処理は作れます。が、マトリックスの場合は「マトリックスのclickedで操作をする」のが基本でしょう。それなら1つの処理だけ考えれば済みますから。
マトリックスには、「現在選択されているセル」に関するプロパティがあります。それは「current cell」というものです。これは、現在選択されているセルの参照となります。これでセルを調べ、そのNameやTitleなどを調べれば、名前や表示されているテキストなどがわかるわけです。
on clicked theObject |
例えば、これは「radio1」というマトリックスで、選択されているボタンセルのタイトル(表示テキスト)をtext1テキストフィールドに書き出す例です。name
of theObjectでオブジェクトの名前をチェックした後、「current cell of theObject」として選択されたセルを取り出しています。そして、「title
of selobj」で選択セルのtitleを変数に取り出し、それをcontents of text field "text1"に設定しています。
もし、それぞれのセルの状態を個別に調べたければ、セルのstateで調べることが可能です。最初に登場した、あのstateですよ。例えば、「state
of cell 1 of matrix "radio1"」というように指定すれば、1番目のセルの状態を調べることができます。もちろん、各セルに名前を付けて、名前で呼び出すことも可能です。
ラジオボタンは、「マトリックスとセル」という独特の考え方が理解できないとなかなか使いこなせないかも知れません。とりあえず、セルということはあまり意識せず、「全体をグループとして扱う『マトリックス』という部品の中にボタンモドキが入っている」という程度に考えて下さい。ちょっと使う分には、ボタンもボタンセルもだいたい一緒ですから。