Geometry 関数
NSBundle
NSDictionary
NSFileManager
NSMutableAttributedString
NSNumber
NSScanner
NSString
NSTimer
Graphic 関数
NSApplication
NSBezierPath
NSCell
NSColor
NSCursor
NSCustomImageRep
NSDocument
NSDocumentController
NSDragging
NSEvent
NSFontManager
NSGraphicsContext
NSImage
NSMenu
NSOutlineView
NSPanel
NSPopUpButton
NSResponder
NSScrollView
NSString 追加
NSTableColumn
NSTableView
-NSTableView に値を設定する
-NSTableView に NSButton を入れる
-NSTableView の中のボタンを機能させる
-NSTableView にアイコンつきテキストを埋め込む
-テーブルの構造
-テーブルのセルに属性を設定する
NSTextStorage
NSTextView
NSToolbar
NSView
NSWindow
NSWorkspace
その他
.nib ウィンドウ
Views パレット
クラス
インスタンス変数
メソッド
CFXML
Carbon Event
Carbon Graphics
Cocoa で日本語
メソッド
その他

- 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
      • NSTableView
    • NSScroller
    • NSScroller
    • NSClipView
      • NSTableHeaderView
    • _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



[Home] [Download] [Archives] [BBS] [Cocoa Programming Tips 1001] [Core Foundation の秘密] [Safari Developer Center] [はじめてのブラウザのつくり方] [Sketch BP] [スクリーンセイバーを作ろう] [Objective-C 最適化] [Authorization API 完全理解] [Mac OS X Programming Books Review] [オブジェクト指向の言語比較論] [panther-dev]

mailto: mkino@xd5.so-net.ne.jp