ページ

2010年4月16日金曜日

Application List (3) アイコン表示

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前回)Cocoaの日々: Application List (2) ファイルパスからアプリ名に変換して表示 - LSCopyDisplayNameForURL

前回はアプリ名を表示した。今回はアイコンを表示してみよう。

まずアイコン画像の用意から。ファイルのアイコン画像は -[NSWorkspace iconForFile:] で取得できる。
NSWorkspace Class Reference - iconForFile:

パスから決めることができるので前回同様 -[ApplicationEntry initWithPath:] 内に仕込む。

ApplicationEntry.m

-(id)initWithPath:(NSString*)aPath
{
self = [super init];
if (self != nil) {
self.path = aPath;
   :
   :
self.icon = [[NSWorkspace sharedWorkspace] iconForFile:path];
[icon setSize:NSMakeSize(16, 16)];
}
return self;
}


取得後に表示用のサイズ(16x16)を設定しておく。



次にこの画像を表示する実装。

NSTableView で画像を表示するには NSImageCell を使うのが簡単だが、これでは同じセル内でアプリ名が表示できない。カスタムセルを作って自前で描画する必要がある。この辺り iPhone では標準のセルで簡単にできるので AppKit の方にも用意して欲しい。

自前描画は以前扱ったことがある。
Cocoaの日々: NSTableView にカスタムビューを表示する (6)カスタムセルにモデルオブジェクトの内容を描画する

関連:
Cocoaの日々: NSTableView にカスタムビューを表示する (5)カスタムセルへ bindings経由でモデルオブジェクトを渡す



描画方法について改めてまとめてみる。

1. NSCell のサブクラスを作る(カスタムセルと呼ぶことにする)

2. 表示したい NSTableColumn にカスタムセルのインスタンスを設定する。

3. NSTableColumn の Value に モデルを bindする

4. カスタムセルに2つのメソッドを実装する
-(void) drawInteriorWithFrame:inView:
-(id)copyWithZone:


詳しく見ていこう。





1. NSCell のサブクラスを作る。

ApplicationCell という名のクラスを作る。

@interface ApplicationCell : NSCell {

}

@end


2. 表示したい NSTableColumn にカスタムセルのインスタンスを設定する

今回は AppListAppDelegate に NSTableColumn へのアウトレットを用意し、アプリ起動時に -[NSTableColumn setDataCell:] で設定してやる。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
:
[tableColumn_ setDataCell:
[[[ApplicationCell allocinitautorelease]];
}





3. NSTableColumn の Value に モデルを bindする

今回は ArrayController を介してモデルとつながっている。
AppListAppDelegate.appList ← Array Controller ← NSTableColumn

Interface Builder で NSTableColumn の Bindings設定を開き、Bind to を Array Controller へ、Key は arrangedObjects、Model Key Path を空にしておく。

Model Key Path を空にしておくのがポイントで、これによって ArrayController が扱う ApplicationEntry のインスタンスを直接セルへ渡せる。

なお ArrayController の方はこうなっている。
appList は AppListAppDelegate で定義されている NSMutableArray を指している。


4. カスタムセルに2つのメソッドを実装する

ApplicationCell.m
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
ApplicationEntry* entry = [self objectValue];
[controlView lockFocus];
NSPoint p1 = cellFrame.origin;
p1.x += 0;
p1.y += 0 + [entry.icon size].height;
[entry.icon compositeToPoint:p1 operation:NSCompositeSourceOver];
NSPoint p2 = cellFrame.origin;
p2.x += 20;
p2.y += 0;
NSDictionary* attrs = [NSDictionary dictionary];
[entry.name drawAtPoint:p2 withAttributes:attrs];
[controlView unlockFocus];
}

- (id)copyWithZone:(NSZone *)zone
{
ApplicationCell* cell = (ApplicationCell*)[super copyWithZone:zone];
return cell;
}



-[NSCell objectValue] でArrayController から渡される ApplicationEntry のインスタンスを取得することができる。
copyWithZone: は必須。これが実装さていないと実行時にエラーとなる(NSTableColumn が使う)。



これで、できあがり。

動かしてみよう。
出た。いい感じだ。

ソースコードは GitHub からどうぞ
AppList at 2010-04-15c from xcatsan's SampleCode - GitHub


(参考)セルに画像とテキストを描く情報はHMDT でも紹介されている。参考まで。

この中の「セルに画像とテキストを描く」の箇所。カスタムセルを用意して drawInteriorWithFrame:inView: をオーバーライドすれば良い。


----
次はドラッグ&ドロップによる並び替え。