NSView on NSCell
できたのでメモ書き
- あらかじめ、InterfaceBuilderで表示させるTableの横幅と、表示させる中身の横幅を決めておく。なお、表示させる中身とTableは別々のNibファイルにしておく事。
- NSCellを継承して、NSViewを保持するような仕組みを持たせる
- NSTableColumnに、NSCellを継承させたオブジェクトを保持させる
- NSTableViewのdataSource先では、「- (int) numberOfRowsInTableView:」「- (void) tableView:willDisplayCell:forTableColumn:row:」を実装させる。
- 「- (void) tableView:willDisplayCell:forTableColumn:row:」の内部では、第二引数のNSCellが継承したオブジェクトなはずなので、「cell setView:」と言った感じでViewを入れる
- NSCellの継承したオブジェクトで「drawWithFrame:inView:」をオーバーライドし、第一引数のNSRect型を保持しているNSViewのsetFrameで指定させ、第二引数のNSViewのメソッド「addSubview:」で保持しているNSViewを追加させる。
注意点
- NSTableViewの更新が、パフォーマンスを理由に全てのCellを見に行かないらしい。つまり、[nstableview display]とやってもcellの中身までは更新しないっぽい。解決として、下記のような力技更新が必要みたい。ただ、明らかにパフォーマンスが遅くなるので注意。
- CocoaBindingしか使ってなかったら泣きの涙。*1
以下、部分的なソース。不要っぽそうな部分は消しているから、所々よくわからないかも。
NSTableViewの解決策っぽい物
- (void) reloadTableView { while ([[self subviews] count] > 0) { [[[self subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay]; } [self reloadData]; }
NSTableViewのDataSource部分
// ============================================================================= #pragma mark NSTableView's datasouce methods. #pragma mark // // - (NSMutableArray*) movieControllers; // 表示するデータを保存し蓄えている。中は、NCDownloadDataというオブジェクト。 // - (int) numberOfRowsInTableView:(NSTableView *) tableView { return [[self movieControllers] count]; } - (void) tableView:(NSTableView *) tableView willDisplayCell:(id) cell forTableColumn:(NSTableColumn *) tableColumn row:(int) row { [(NCDownloadCell *)cell setNCDownloadData:(NCDownloadData*)[[self movieControllers] objectAtIndex: row]]; }
NSCellを継承したオブジェクト
@interface NCDownloadCell : NSCell { @private NCDownloadData* __ncdc_data; id _delegate; NSView* _ncdc_view; } - (void) setNCDownloadData:(NCDownloadData*)data; - (NCDownloadData*) downloadData; - (void) setDelegate:(id)dele; - (id) delegate; @end @implementation NCDownloadCell - (id)init { self = [super init]; if (self) { // Initialization code here. __ncdc_data = nil; _ncdc_view = nil; } return self; } - (void) dealloc { if (__ncdc_data) [__ncdc_data release], __ncdc_data = nil; if (_ncdc_view) [_ncdc_view release], _ncdc_view = nil; [super dealloc]; } // ============================================================================= // Cellの内容を表示させる - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { [super drawWithFrame:cellFrame inView:controlView]; NSView* v = [__ncdc_data view]; [v setFrame:cellFrame]; if ([v superview] != controlView) { _ncdc_view = v; [controlView addSubview:_ncdc_view]; } MyAssert1(@"drawWithFrame: ncdc_data: %@", __ncdc_data); MyAssert1(@"drawWithFrame: _ncdc_view: %@", _ncdc_view); } // ============================================================================= - (void) setNCDownloadData:(NCDownloadData*)data { @synchronized (__ncdc_data) { if (__ncdc_data == nil || __ncdc_data != data) { if (__ncdc_data) [__ncdc_data release], __ncdc_data = nil; __ncdc_data = [data retain]; [__ncdc_data setDelegate:self]; } } } - (NCDownloadData*) downloadData { return __ncdc_data; } // ============================================================================= - (void) setDelegate:(id)dele { @synchronized (_delegate) { if (_delegate != dele) _delegate = [dele retain]; } } - (id) delegate { return _delegate; } @end
NCDownloadData(データそのもの)
なおNCDownloadDataは、downloadContentsView.nibではfilesOwnerになっている。
NCDownloadDataViewはNSViewの継承クラス。
@interface NCDownloadData : NSWindowController <NCMovieDownloadStatePassing> { IBOutlet NCDownloadDataView* _ncdd_viewer; @private double _nd_counter; double _nd_len; id _nd_delegate; } - (void) setDelegate:(id)obj; - (id) delegate; - (NSView*) view; // some methods... @end @implementation NCDownloadData - (id) init { // self = [super initWithWindowNibName:@"downloadContentsView"]; // I don't know why not run this. self = [super init]; if (!self) return nil; // 表示させる中身のNibファイルの読み込み。 if (![NSBundle loadNibNamed:@"downloadContentsView" owner: self]) { MyAssert(@"init Error !!"); [self release]; return nil; } MyAssert(@"Init"); _nd_len = 0.0; _nd_counter = 0.0; _nd_delegate = nil; return self; } - (void) dealloc { [super dealloc]; } - (NSView*) view { return _ncdd_viewer; } // has a meny methods ... @end
*1:つか、何か良い方法ないかなー。CocoaBindingを自作できるほど技量ねぇし…