(前回)Cocoaの日々: NSTableView にカスタムセルを表示する (11) ボタンをつける〜NSCellのマウスイベントの扱い
NSTableView のサブクラスを作り、ここでマウスイベントを拾うことにした。
コード
移動中のマウスの動きもトラッキングしたい。Mac OS X v10.5 以降は NSTrackingArea が用意されているのでこれを使う。
(参考)Cocoaの日々: NSTrackingArea
CustomTableView.h
@interface CustomTableView : NSTableView {
NSTrackingArea* trackingArea;
}
@property (retain) NSTrackingArea* trackingArea;
@end
トラッキング対象となるエリア(NSTrackingArea) はリサイズなどで頻繁に変わる。更新の為には古いエリアを解放する必要があるのでメンバ変数でとっておく。
CustomTableView.m
NSTrackingArea 更新用のメソッドを用意し、これをリサイズ時に呼び出すようにする。
- (void)updateTrackingArea
{
if (self.trackingArea) {
[self removeTrackingArea:self.trackingArea];
}
self.trackingArea = [[[NSTrackingArea alloc]
initWithRect:[self frame]
options:(NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingActiveAlways )
owner:self
userInfo:nil] autorelease];
[self addTrackingArea:self.trackingArea];
}
一旦 NSTrackingArea が設定できれば mouseEntered: や mouseMoved: などが呼び出される。これらを実装しておく。今回は検証目的なので NSLog() を入れておいた。
実行結果
実行してみよう。
マウスをテーブルの上に持っていくとイベントが取れているのがわかる。
トラッキング範囲
なお NSTableView は NSScrollView の中に入っているため、トラッキングエリアに -[NSTableView frame] を指定すると NSTableViewの外まで対象となってしまう(理由:NSTableViewの大きさ > NSScrollViewの大きさ)。サンプルアプリの場合、ウィンドウ下の余白までが入ってしまう。これを防ぐ為に -[NSView visibleRect] を使うことも考えたが、今度は NSTableView でスクロールするとその範囲が古くなってしまうため意図通りに動かない(スクロールで新しく現れた範囲がトラッキングの対象にならない)。スクロールの度に NSTrackingArea を更新するのも気が乗らない。
今回は -[NSTableView frame] で隠れた部分も含め NSTableView 全体を範囲としておき、イベント処理時に見える範囲(visibleRect)内かどうかのチェックを行うようにした。
- (BOOL)isVisible:(NSEvent*)theEvent
{
NSPoint p = [self convertPointFromBase:[theEvent locationInWindow]];
return NSPointInRect(p, [self visibleRect]);
}
- (void)mouseEntered:(NSEvent *)theEvent
{
if ([self isVisible:theEvent]) {
NSLog(@"mouseEntered:");
}
[super mouseEntered:theEvent];
}
なお NSTrackingArea で大きな範囲をとっても、ウィンドウの外はトラッキングの対象にはならない。
ソースコード
GitHub からどうぞ
CustomCellWithCoredata at 20091214 from xcatsan's SampleCode - GitHub