|
- Application Kit-
NSTableView
Application Kit - NSTableView
NSTableView に値を設定する
Keywords: numberOfRowsInTableView, objectValueForTableColumn
テーブルに値を設定するにはどうするか?dataSource のメソッドをオーバーライドするんだ。かならず実装しなきゃいけないのは、以下の 2 つ。
Application Kit/NSTableView.h
- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
最初の numberOfRowsInTableView: は、行がいくつあるのかを指定するんだ。2 つなら 2 を返せばいい。当然か。
次の tableView:objectValueForTableColumn:row: は、テーブルに入るオブジェクトを返すんだ。そのオブジェクトはテーブルのどこに入るのか?このメソッドの引き数で指定されているんだ。行は rowIndex で、列は aTableColumn で指定されている。うん?ちょっと待った。行は int 型だから分かるよね。じゃ、列は?いったい何列目なんだ。列は NSTableColumn で指定されるんだけど、こいつには identifier っていう便利なものがある。
まず Interface Builder に戻って、NSTableColumn に identifer を指定するんだ。テーブルのヘッダのところをダブルクリックすると、NSTableColumn が Inspector に現れる。それの identifer に、適当な文字列を指定するんだ。
そうやって準備した後、このメソッドで、NSTableColumn の identifier メソッドを使う。
Application Kit/NSTableColumn.h
- (id)identifier;
これで比較すれば、テーブルのどのセルを指定しているのかがわかるぜ。
じゃ、サンプルだ。
TableController.m (Sample)
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 5;
}
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
// 'on' の列
if([[aTableColumn identifier] isEqualToString:@"no"]) {
return [NSNumber numberWithInt:rowIndex];
}
// 'no' の列
else if([[aTableColumn identifier] isEqualToString:@"name"]) {
switch(rowIndex) {
case 0: return @"A Perfect Day";
case 1: return @"Uncle Wiggily";
case 2: return @"Just Before the War";
case 3: return @"The Laughing";
case 4: return @"Dinghy";
}
}
// ここには来ないはず
return nil;
}
このサンプルでは、テーブルに 2 つの列があるんだ。それぞれに "no" と "name" という identifer を指定しておく。
上で示した 2 つのメソッドが実装されているんだ。まず、numberOfRowsInTableView: では、行の数を返す。ここでは、とりあえず、決め打ちで 5 を返してる。
そして、tableView:objectValueForTableColumn:row: では、NSTableColumn の identifier を調べて、返すオブジェクトを決定している。まず、"no" のときは、rowIndex から NSNumber オブジェクトを作って返す。行番号になるわけだ。次に "name" のときは、用意してある文字列を返すんだ。
Application Kit - NSTableView
NSTableView に NSButton を入れる
Keywords: setDataCell
なるほど。上で、tableView:objectValueForTableColumn: で、オブジェクトを返せば、そこに値が入るのは分かった。これは、テーブルのそれぞれのマスに、テキストを表示する NSCell がある、っていうことなんだ。じゃ、たとえば、そのテキストのセルの代わりに、ボタンの Cell、つまり、NSButtonCell を入れるにはどうしたらいいのか?それには、NSTableColumn の setDataCell: メソッドを使う。
Application Kit/NSTableColumn.h
- (void)setDataCell:(NSCell *)aCell;
これを使うと、その列に表示するセルを設定することができる。NSButtonCell を指定すれば、ボタンが表示されるってわけだ。
さっそく、サンプルを。
TableController.m (Sample)
- (void)awakeFromNib
{
NSTableColumn* tableColumn;
NSButtonCell* buttonCell;
tableColumn = [_tableView tableColumnWithIdentifier:@"on"];
buttonCell = [[NSButtonCell alloc] init];
[buttonCell setButtonType:NSSwitchButton];
[buttonCell setTitle:@""];
[tableColumn setDataCell:buttonCell];
[buttonCell release];
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 5;
}
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
// 'on' の列
if([[aTableColumn identifier] isEqualToString:@"on"]) {
return [NSNumber numberWithInt:(rowIndex % 2)];
}
// 'no' の列
else if([[aTableColumn identifier] isEqualToString:@"no"]) {
return [NSNumber numberWithInt:rowIndex];
}
// 'name' の列
else if([[aTableColumn identifier] isEqualToString:@"name"]) {
switch(rowIndex) {
case 0: return @"A Perfect Day";
case 1: return @"Uncle Wiggily";
case 2: return @"Just Before the War";
case 3: return @"The Laughing";
case 4: return @"Dinghy";
}
}
// ここには来ないはず
return nil;
}
上のソースと似ているけど、いくつか違うところがある。まず、インスタンス変数に NSTableView へのポインタを持っているんだ。これは、Interface Builder で設定しておく。
次に、awakeFromNib が追加されている。この中で、ボタンを設定しているんだ。まず _tableView から NSTableColumn を取得する。NSButtonCell のインスタンスを作成する。そして、NSTableColumn に setDataCell: で設定するんだ。
ボタンが選択されているか、いないかは、:objectValueForTableColumn: で設定されるよ。
Application Kit - NSTableView
NSTableView の中のボタンを機能させる
Keywords: setObjectValue
上の例では、ボタンとして、NSSwitchButton を設定してみた。このボタンは、トグル的に動くはずなんだけど、上のコードだと、トグルしないことが分かるはずだ。だめじゃん。と、いうわけで、これを動作するようにしてみよう。
作戦は、こうだ。ボタンを押すと、ボタンの持っている値が変わる。すると、NSButtonCell は NSTableView の tableView:setObjectValue:: を呼び出すんだ。
Application Kit/NSTableView.h
- (void)tableView:(NSTableView *)tableView
setObjectValue:(id)object
forTableColumn:(NSTableColumn *)tableColumn
row:(int)rowIndex;
このメソッドは、テーブルの中の値が変更されたときに呼び出されるんだ。ここから、ボタンの値を取り出して、保存しておく。そして、tableView:objectValueForTableColumn: で、その値を返してやればいいんだ。
じゃ、コードだ。このコードは「NSTableView に NSButton を入れる」に追加をしたものだ。
TableController.m (Sample)
- (void)awakeFromNib
{
...
// _on[] を初期化する
memset(_on, 0, sizeof(_on));
}
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
// 'on' の列
if([[aTableColumn identifier] isEqualToString:@"on"]) {
return [NSNumber numberWithInt:_on[rowIndex]];
}
...
}
- (void)tableView:(NSTableView *)tableView
setObjectValue:(id)object
forTableColumn:(NSTableColumn *)tableColumn
row:(int)rowIndex;
{
id identifier;
identifier = [tableColumn identifier];
if([identifier isEqualToString:@"on"]) {
_on[rowIndex] = [object intValue];
}
}
まず、インスタンス変数 _on[] を追加している。これは、ボタンの状態を保存しておくためのものだ。もちろん、NSMutableArray に変更してもいいよ。これを awakeFromNib で初期化している。
そして、まずボタンから値を取り出す。それが、最後の関数、tableView:setObjectValue: だ。このメソッドの引き数 object が、新しく設定される値だ。これを int 型にして、_on[] に入れておく。
順番が前後するけど、メソッド tableView:objectValueForTableColumn:row: で、その値を返してやる。
これで、ボタンが機能するようになるよ!ボタンの現在の値は、_on[] からとりだすことになる。
Application Kit - NSTableView
NSTableView にアイコンつきテキストを埋め込む
Keywords: IconedCell, dataCell
NSTableView に画像付きテキストを埋め込んでみよう。ほら、Finder にあるような、アイコンがあって、ファイル名が書いてあるようなやつ。あれを作ってみよう。
それには、画像とテキストを表示できる NSCell を使う。これの作り方はこちらを見てくれ。ここでは、この IconedCell を使うことを前提に話を進めるよ。
まず、初期化のところで、NSTableColumn の dataCell として、この IconedCell を設定する。そして、dataSource の objectValueForTableColumn:: のところで、画像を設定して、テキストを objectValue として返すんだ。
今回のサンプルコードは 2 つのソースを使う。1 つは、NSTableView を継承したクラス。もう 1 つは、NSTableView の dataSource となるクラスだ。あ、もちろん、IconedCell のコードも必要だよ。
IconedTableView.m (Sample)
- (void)awakeFromNib
{
NSTableColumn* tableColumn;
// IconedCell を 'name' の列に設定する
IconedCell* iconedCell;
iconedCell = [[[IconedCell alloc] init] autorelease];
tableColumn = [self tableColumnWithIdentifier:@"name"];
[tableColumn setDataCell:iconedCell];
}
IconedTableDataSource.m (Sample)
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(int)rowIndex
{
id identifier;
NSString* path = @"/Application/Sherlock.app";
identifier = [tableColumn identifier];
if([identifier isEqualToString:@"name"]) {
NSCell* cell;
cell = [tableColumn dataCell];
[cell setImage:[[NSWorkspace sharedWorkspace]
iconForFile:path]];
return [path lastPathComponent];
}
// ここには来ないはず
return @"";
}
まず、NSTableView のクラスでは、awakeFromNib をオーバーライドして、ここで初期化を行っている。ここでは、"name" っていう identifier のついた NSTableColumn を取り出すんだ。そして、IconedCell を dataCell として、設定する。
次に、dataSource の objectValueForTableColumn:: では、IconedCell に値を設定している。ここでは、画像として、Sherlock のアイコンを、テキストして、"Sherlock.app" を設定しているよ。まず、identifier を調べる。"name" だったら、dataCell を取り出す。これが、実は IconedCell になっているんだ。そして、setImage: で画像を設定する。最後に、"Sherlock.app" をテキストとして返す。
あとは、IconedCell が描画をしてくれるんだ。
Application Kit - NSTableView
テーブルの構造
Keywords: structure
Interface Builder を使ってテーブルを作ると、もう、一式揃っているよね。スクロールバーが付いていて、ヘッダが付いてて、テーブルもある。これは、いったいどれだけの View から構成されているのか?
一番トップにあるのは NSScrollView だ。NSTableView じゃないので注意。そこから View の階層構造を探ってみると、
- NSScrollView
- NSClipView
- NSScroller
- NSScroller
- NSClipView
- _NSCornerView
という構造になってる。NSScrollView の中に、NSTableView と NSTableHeaderView があるんだ。_NSCornerView っていうのは、右上の部分ね。
Application Kit - NSTableView
テーブルのセルに属性を設定する
Keywords: willDisplayCell
NSTableView を使っていると、セルに動的に属性を設定したいときがあるでしょ。たとえば、テキストの内容によってフォントを変えたいとか、バックグラウンドの色を変えたいとか。それには NSTableView の delegate のメソッドである tableView:willDisplayCell:forTableColumn:row: を使おう。
Application Kit/NSTableView.h
- (void)tableView:(NSTableView *)tableView
willDisplayCell:(id)cell
forTableColumn:(NSTableColumn *)tableColumn
row:(int)row;
このメソッドはセルを表示する前に呼び出される。引数の cell から値を取り出して、適当な属性を設定してやればいい。
ということで、サンプル。このサンプルでは、テーブルの列ごとに色をつけてみた。偶数の列は白で、奇数の列は淡いグレーだ。

このサンプルの tableView:willDisplayCell:forTableColumn:row: の実装はこうなっている。
(sample)
static NSColor* _whiteColor = nil;
static NSColor* _stripeColor = nil;
- (void)tableView:(NSTableView*)tableView
willDisplayCell:(id)cell
forTableColumn:(NSTableColumn*)tableColumn
row:(int)row
{
if (!_whiteColor) {
_whiteColor = [NSColor whiteColor];
_stripeColor =
[[NSColor colorWithCalibratedWhite:0.95 alpha:1.0]
retain];
}
// セルの背景色を設定する
[cell setDrawsBackground:YES];
if (row % 2 == 1) {
[cell setBackgroundColor:_stripeColor];
}
else {
[cell setBackgroundColor:_whiteColor];
}
}
引数として渡される row の値から偶数列か奇数列かを判断して、cell に色を付けているんだ。
■サンプルダウンロード:
StripeColorCell.tar.gz
|