Минимальные требования:
- После нажатия левой кнопки мыши на кнопку она должна отображаться нажатой, когда мышь находится над ней.
- Если мышь отпустит кнопку, ваша клетка должна отправить соответствующее сообщение о действии.
Чтобы кнопка выглядела нажатой, вам необходимо соответствующим образом обновить свойство highlighted
ячейки кнопки. Изменение только состояния не приведет к этому, но вы хотите, чтобы кнопка была выделена, если и только если ее состояние равно NSOnState
.
Чтобы отправить сообщение о действии, вам нужно знать, когда мышь отпущена, и затем использовать -[NSApplication sendAction:to:from:]
для отправки сообщения.
Чтобы иметь возможность отправлять эти сообщения, вам необходимо подключиться к методам отслеживания событий, предоставляемым NSCell
. Обратите внимание, что все эти методы отслеживания, за исключением последнего метода -stopTracking:...
, возвращают логическое значение, чтобы ответить на вопрос: «Вы хотите продолжать получать сообщения отслеживания?»
Последний поворот заключается в том, что для того, чтобы вообще отправлять какие-либо сообщения отслеживания, вам необходимо реализовать -hitTestForEvent:inRect:ofView:
и вернуть соответствующую битовую маску из NSCellHit...
значений. В частности, если возвращенное значение не имеет значения NSCellHitTrackableArea
, вы не получите никаких сообщений об отслеживании!
Итак, на высоком уровне ваша реализация будет выглядеть примерно так:
- (NSUInteger)hitTestForEvent:(NSEvent *)event
inRect:(NSRect)cellFrame
ofView:(NSView *)controlView {
NSUInteger hitType = [super hitTestForEvent:event inRect:cellFrame ofView:controlView];
NSPoint location = [event locationInWindow];
location = [controlView convertPointFromBase:location];
// get the button cell's |buttonRect|, then
if (NSMouseInRect(location, buttonRect, [controlView isFlipped])) {
// We are only sent tracking messages for trackable areas.
hitType |= NSCellHitTrackableArea;
}
return hitType;
}
+ (BOOL)prefersTrackingUntilMouseUp {
// you want a single, long tracking "session" from mouse down till up
return YES;
}
- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
// use NSMouseInRect and [controlView isFlipped] to test whether |startPoint| is on the button
// if so, highlight the button
return YES; // keep tracking
}
- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView {
// if |currentPoint| is in the button, highlight it
// otherwise, unhighlight it
return YES; // keep on tracking
}
- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag {
// if |flag| and mouse in button's rect, then
[[NSApplication sharedApplication] sendAction:self.action to:self.target from:controlView];
// and, finally,
[buttonCell setHighlighted:NO];
}