NSCellはNSControlと共に使用されるのが一般的です。しかし、NSControlに対して依存性がある訳ではないので、汎用的に使うことができます。今回は、先ほど作ったトラックパッド・コントロールにスライダーセルを付けてみます。
まず最初に、NSSliderCellオブジェクトを生成します。
@interface MyViewWithCell : NSView
{
...
NSSliderCell* xSlider;
NSSliderCell* ySlider;
}
...
@end
- (id)initWithFrame:(NSRect)frameRect
{
...
xSlider = [[NSSliderCell alloc] init];
ySlider = [[NSSliderCell alloc] init];
...
return self;
}
特別なところが何も無いコードです。単純に、ビューのインスタンス変数として定義し、-initWithFrame:内でオブジェクトを生成しています。
ビュー上にセルを乗せる場合は、ビュー内のどの領域にセルが配置されるのかを決めておかなければなりません。
- (NSRect)padRect
{
NSRect rect;
rect.origin = NSMakePoint(0.0, 20.0);
rect.size.width = [self bounds].size.width - 20.0;
rect.size.height = [self bounds].size.height - 20.0;
return rect;
}
- (NSRect)xSliderRect
{
return NSMakeRect(0.0, 0.0, [self bounds].size.width - 20.0, 20.0);
}
- (NSRect)ySliderRect
{
NSRect rect;
rect.origin = NSMakePoint([self bounds].size.width - 20.0, 20.0);
rect.size = NSMakeSize(20.0, [self bounds].size.height - 20.0);
return rect;
}
今回は、xSliderRectとySliderRectメソッドでセル領域を計算して返すようにしてみました。また、ビューのトラックパッド領域も同じくpadRectメソッドで返すようにしてます。
セルを描画するためには、セルを描画したいタイミングで、通常は-drawRect:内で-drawWithFrame:inView:を呼びます。
- (void)drawRect:(NSRect)aRect
{
...
[xSlider drawWithFrame:[self xSliderRect] inView:self];
[ySlider drawWithFrame:[self ySliderRect] inView:self];
}
第一パラメータの領域内にセルのグラフィックが描画されます。セルは、ビュー内部を描画する際のグラフィック・パーツのような感覚で使うことができます。
マウスによってセルを操作する場合は、マウスカーソルの位置によって処理を分岐させる必要があります。そして、マウスカーソルがセルの領域内にあるときは、-trackMouse:inRect:ofView:untilMouseUp:を呼んで、セルにマウスイベントを渡します。
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint locationInWindow = [theEvent locationInWindow];
NSPoint location = [self convertPoint:locationInWindow fromView:nil];
if(NSPointInRect(location, [self padRect]))
{
[self updateValueWithEvent:theEvent];
}
if(NSPointInRect(location, [self xSliderRect]))
{
[xSlider trackMouse:theEvent
inRect:[self xSliderRect]
ofView:self
untilMouseUp:YES];
}
if(NSPointInRect(location, [self ySliderRect]))
{
[ySlider trackMouse:theEvent
inRect:[self ySliderRect]
ofView:self
untilMouseUp:YES];
}
}
スライダーセルなどのように、ドラッグ操作をサポートしているセルもありますが、それらのためにドラッグイベントを渡す必要はありません。-trackMouse:inRect:ofView:untilMouseUp:の中でドラッグも含めて全て処理してくれます。
セルの操作によってセルの値が変化すると、セルからアクションが送信されるようになっています。これをビュー自身で受信することで、セルの値変更時の処理を行うことができます。
- (id)initWithFrame:(NSRect)frameRect
{
...
xSlider = [[NSSliderCell alloc] init];
[xSlider setTarget:self];
[xSlider setAction:@selector(sliderAction:)];
ySlider = [[NSSliderCell alloc] init];
[ySlider setTarget:self];
[ySlider setAction:@selector(sliderAction:)];
...
}
- (void)sliderAction:(id)sender
{
self.value = NSMakePoint([xSlider floatValue], [ySlider floatValue]);
if(action != nil)
{
[NSApp sendAction:action to:target from:self];
}
}
セルの生成と同時にターゲット&アクションを設定します。今回はアクションを受信したら、コントロール値を更新し、ビューの外に向けてアクションを送信しています。