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...
  }
}
posted @ 2016-03-10 17:50  无枝大树  阅读(1760)  评论(0编辑  收藏  举报