Cocoa处理mouse事件
Apple的《Handling Mouse Events》文档中有几个列子记录一下
Listing 4-2 Simple handling of mouse click—sending an action message
- (void)mouseDown:(NSEvent *)theEvent {
|
[self setFrameColor:[NSColor redColor]];
|
[self setNeedsDisplay:YES];
|
}
|
- (void)mouseUp:(NSEvent *)theEvent {
|
[self setFrameColor:[NSColor greenColor]];
|
[self setNeedsDisplay:YES];
|
[NSApp sendAction:[self action] to:[self target] from:self];
|
}
|
- (SEL)action {return action; }
|
- (void)setAction:(SEL)newAction {
|
action = newAction;
|
}
|
- (id)target { return target; }
|
- (void)setTarget:(id)newTarget {
|
target = newTarget;
|
}
|
处理鼠标拖拽操作:
Application Kit一般有两种方法处理鼠标拖动事件:
第一种方法重载NSResponder中mouseDown:
, mouseDragged:
, mouseUp:(用鼠标左键操作)。每个拖拽动作下,首先Application Kit发送一个MouseDown消息给NSResponder对象,接着发送一个或者多个mouseDragged消息,最后发送一个mouseUp:消息。
第二种方法将鼠标拖动系列事件当作一个单一的事件处理,NSResponder通常必须创建事件循环机制获取鼠标事件, NSApplication和NSWindow 都有
nextEventMatchingMask:untilDate:inMode:dequeue:
方法获取事件。
这两种方法都有自己的优点和缺点。在应用程序拖动操作期间接管鼠标跟踪循环处理事件。然而,应用程序的主线程无法处理其他事件和NSTimer也不会触发。鼠标跟踪方法更有效,因为它通常需要更少的代码,允许所有拖动变量是局部。然而,所有拖动代码在子类中继承更困难。
而重载mouseDown:
, mouseDragged:
, mouseUp:方法相比前一种方法,更逻辑更清晰,范围也明确,子类也容易继承处理鼠标拖动事件。
下面是重载mouseDown:
, mouseDragged:
, mouseUp:
- (void)mouseDown:(NSEvent *)theEvent {
|
// mouseInCloseBox and trackingCloseBoxHit are instance variables
|
if (mouseInCloseBox = NSPointInRect([self convertPoint:[theEvent locationInWindow] fromView:nil], closeBox)) {
|
trackingCloseBoxHit = YES;
|
[self setNeedsDisplayInRect:closeBox];
|
}
|
else if ([theEvent clickCount] > 1) {
|
[[self window] miniaturize:self];
|
return;
|
}
|
}
|
- (void)mouseDragged:(NSEvent *)theEvent {
|
NSPoint windowOrigin;
|
NSWindow *window = [self window];
|
if (trackingCloseBoxHit) {
|
mouseInCloseBox = NSPointInRect([self convertPoint:[theEvent locationInWindow] fromView:nil], closeBox);
|
[self setNeedsDisplayInRect:closeBox];
|
return;
|
}
|
windowOrigin = [window frame].origin;
|
[window setFrameOrigin:NSMakePoint(windowOrigin.x + [theEvent deltaX], windowOrigin.y - [theEvent deltaY])];
|
}
|
- (void)mouseUp:(NSEvent *)theEvent {
|
if (NSPointInRect([self convertPoint:[theEvent locationInWindow] fromView:nil], closeBox)) {
|
[self tryToCloseWindow];
|
return;
|
}
|
trackingCloseBoxHit = NO;
|
[self setNeedsDisplayInRect:closeBox];
|
}
|
下面跟踪鼠标循环方式,处理拖拽事件:(简单例子)
- (void)mouseDown:(NSEvent *)theEvent {
|
BOOL keepOn = YES;
|
BOOL isInside = YES;
|
NSPoint mouseLoc;
|
while (keepOn) {
|
theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask |
|
NSLeftMouseDraggedMask];
|
mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
isInside = [self mouse:mouseLoc inRect:[self bounds]];
|
switch ([theEvent type]) {
|
case NSLeftMouseDragged:
|
[self highlight:isInside];
|
break;
|
case NSLeftMouseUp:
|
if (isInside) [self doSomethingSignificant];
|
[self highlight:NO];
|
keepOn = NO;
|
break;
|
default:
|
/* Ignore any other kind of event. */
|
break;
|
}
|
};
|
return;
|
}
|
下面跟踪鼠标循环方式,处理拖拽事件:(复杂例子)
- (void)mouseDown:(NSEvent *)theEvent
|
{
|
if ([theEvent modifierFlags] & NSAlternateKeyMask) {
|
BOOL dragActive = YES;
|
NSPoint location = [renderView convertPoint:[theEvent locationInWindow] fromView:nil];
|
NSAutoreleasePool *myPool = nil;
|
NSEvent* event = NULL;
|
NSWindow *targetWindow = [renderView window];
|
myPool = [[NSAutoreleasePool alloc] init];
|
while (dragActive) {
|
event = [targetWindow nextEventMatchingMask:(NSLeftMouseDraggedMask | NSLeftMouseUpMask)
|
untilDate:[NSDate distantFuture]
|
inMode:NSEventTrackingRunLoopMode
|
dequeue:YES];
|
if(!event)
|
continue;
|
location = [renderView convertPoint:[event locationInWindow] fromView:nil];
|
switch ([event type]) {
|
case NSLeftMouseDragged:
|
annotationPeel = (location.x * 2.0 / [renderView bounds].size.width);
|
[imageLayer showLens:(annotationPeel <= 0.0)];
|
[peelOffFilter setValue:[NSNumber numberWithFloat:annotationPeel] forKey:@"inputTime"];
|
[self refresh];
|
break;
|
case NSLeftMouseUp:
|
dragActive = NO;
|
break;
|
default:
|
break;
|
}
|
}
|
[myPool release];
|
} else {
|
// other tasks handled here......
|
}
|
}
|
下面跟踪鼠标循环方式,处理拖拽事件:(经典例子)
- (void)mouseDown:(NSEvent *)theEvent {
|
NSPoint pos;
|
while ((theEvent = [[self window] nextEventMatchingMask:
|
NSLeftMouseUpMask | NSLeftMouseDraggedMask])) {
|
NSPoint pos = [self convertPoint:[theEvent locationInWindow]
|
fromView:nil];
|
if ([theEvent type] == NSLeftMouseUp)
|
break;
|
// Do some other processing...
|
}
|
}
|