Continuous
2009/07/21
ここでは次のような読者を想定している。
なお XMouse にはマウスイベントについての初等的な解説があるので合わせて読むと理解が深まるかも知れない。
XSlider は非常に小さなサンプルプログラムである。Xcode と Interface builder の最初の学習には、このくらいがちょうど良い。
図1. XSlider の実行画面
仕様
この程度の事にプログラムコードを書く必要は無い。
最初に Xcode でプロジェクト XSlider
を作る。プロジェクトとしては Cocoa Application を選択する。
Xcode は /Developer/Applications/
に置かれている。開くとチュートリアル "Welcome ..." 画面が現れるが、これは閉じて、「ファイルメニュー」から「新規プロジェクト」を開き、プロジェクト名を付ける。
図2. Xcode の「NIB ファイル」
「NIBファイル」の中の「MainMenu.xib」を開くとウインドウが現れる(図2)。ウインドウに載せるパーツ(オブジェクト)は Interface Builder の Tools → Library から選ぶ。
  | ||
図3a. スライダーから control-drag でテキストフィールドに繋ぐ |   | 図3b. ドラッグを止めるとメニューが現れるtakeFloatValueFrom: を選ぶ |
オブジェクトを controll-click すると connections panel
が現れる*。
  | ||
図4a. スライダーの connections panel |   | 図4b. テキストフィールドの connections panel |
コンパイルして実行する。
Lesson 2 ではスライダーの変化をプログラムで捉え、その値を読み取り、テキストフィールドに書き出す。
いくつかのステップに分けて作業を進めていく。
Xcode の「ファイル」メニューから「新規ファイル」を開く。(生成するファイルの保存先として「クラス」を指定しておく)
図5. Xcode の「グループとファイル」
「Objective-C NSView subclass」を選択し*、ファイルを保存する。
ファイル名としては、ここでは(簡単な例題なので) XSlide.m
とする。すると XSlider.h
と XSlider.m
が作成される。
Object-C Class
ではダメらしい。自動生成された XSlider.h
の XSlider
クラスにインスタンス変数とメソッドを追加する。インスタンス変数としてはスライダーとテキストフィールドへのポインタ、メソッドはスライダーが変化した時のメッセージを受け取るためのものが必要である。ここでは各々 slider
、aField
および setfield
としている。(もっと適切な名前があったであろう)
#import <Cocoa/Cocoa.h> @interface XSlider : NSView { IBOutlet NSSlider *slider; IBOutlet NSTextField *aField; } - (IBAction)setField:(id)sender; @end
slider.m
にメソッド setField
の内容を追加する。
#import "XSlider.h" @implementation XSlider - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code here. } return self; } - (void)drawRect:(NSRect)rect { // Drawing code here. } - (IBAction)setField:(id)sender { float v; /* set the text field to correspond to the current value of the slider */ //NSRunAlertPanel(@"Message", @"slider changed!", nil, nil, nil); //if(!slider) NSRunAlertPanel(@"Message", @"slider nil", nil, nil, nil); v = [slider floatValue]; //NSRunAlertPanel(@"Message",[NSString stringWithFormat:@"%f",v], nil, nil, nil); //if(!aField) NSRunAlertPanel(@"Message", @"aField nil", nil, nil, nil); [aField setStringValue:[NSString stringWithFormat:@"%f",v]]; } @end
デバッグのためのコードが含まれているが、役に立つかも知れない。
コンパイルする
XSlider
を実行し、スライダーのノブを移動した時にメッセージが setfield
に届く事を確認する。実はここが(初心者の僕にとって)最も難しい課題であった。僕はソースコードと Interface Builder で表示されるオブジェクトの関係がなかなか分からなかったのである。
alert panel はこのような場合のデバッグに便利である。setfield
の中の最初の NSRunAlertPanel
のコメントを外しておけば、メッセージが届いた時に
slider changed!
のメッセージが表示されるはずである。
Interface Builder はソースコードをどのようにしてビジュアルに表示されているオブジェクトと結び付けているのか?
ウインドウのパネル(トップバーではない!)を選択してインスペクターを覗くと Class
が表示される(下図)。この内容をソースコードの中の Class
名に変更する。図のボタン ▼ をクリックすれば一覧の中に XSlider
が見えるはずである。XSlider
を選べば Class Actions と Class Outlets の中に、ソースコードの中で指定された内容が表示される。
図6. ウインドウパネルのインスペクタ情報
なお、インスペクターのトップバーが Slider Identity
となっているが、この Slider
は XSlider
から X
を除去した文字列である。
ソースコードの中の slider
の値はこのままでは NULL
である。これに実体(メモリ)を割り当てなくてはならない。この作業はソースコードの中の slider
がウインドウの中のスライダーである事を教える事によって初期化時に自動的に行われるはずである。
ウインドウのパネル(トップバーではない!)を control-click して connections panel を表示させる。すると Outlets の中に slider
が表示されるので、これをウインドウの中のスライダーにドラッグする。(下図)
図7. コード中の slider を実体と結びつける
ついでに、aField
も同様な方法でウインドウのテキストフィールドと結びつけておく。(上の図では結びつけられた結果が表示されている)
スライダーのノブを移動した時に、setField
にメッセージが届かなくてはならない。First Responder
の connections panel を開くと setField:
が含まれている。スライダーにドラッグする。(下図)
図8. スライダのアクションの先を指定する
注: 実は setField:
はウインドウ(Slider
)の connections panel の中にも存在する。どちらの setField:
をスライダーと結びつけても実行結果に違いは見当たらない。僕には今のところ、使い方の違いを知らない。2つの setField
を同時にはスライダーに結びつける事はできない。
以上で正しく実行されるはずである。
旨く行かない時には実装コードのコメントを外してみる。どこで問題が発生しているかが分かるはずである。
デバッグに、データの値を表示するコードを含めるのは初等的ではあるが、基本的でもある。ただ NSRunAlertPanel
は大袈裟だし、使い辛い。もっと手軽で、強力な方法は、C の標準出力関数である printf()
を利用する事である。そのためには XSlider.h
の中に
#import <stdio.h>
を含める。さらに、標準出力が見えるようにコマンドラインで実行する。そのためには...
図9. XSlider.app
の場所
control-click で「パッケージの内容を表示」を選ぶ。
図10. XSlider.app
の中の XSlider
この XSlider
をコマンドラインから実行すれば printf()
の出力が見える。さらに実行時のエラーも表示される事がある。
Continuous
2009/07/23
デフォルトのスライダーの設定では、ノブを離した時にしか変化を伝えられない。この設定は通常は都合が悪いであろう。ノブ位置の変化をリアルタイムでアプリケーションに伝達するにはスライダーのアトリビュートで "Continuous" にチェックマークを付ける。
図11. スライダーのアトリビュート
2009/07/23
View クラスとは平たく言えば見えるもののクラスだと考えてよい*。それらは大きさや位置を表す共通の内部変数を持っている。Cocoa における View クラスの実装である NSView クラスでは見えるものは矩形(rectangle)で囲まれており、これを frame と呼んでいる。NSView クラスのインスタンスは全て frame 情報を返す frame
メソッドを持っている。frame と良く似たものに bounds がある。この違いに関しては以下の文献 "View Geometry" に詳しい。