English 中文(简体)
Catching double click in Cocoa OSX
原标题:

NSResponder seems to have no mouse double click event. Is there an easy way to catch a double click?

最佳回答

The mouseDown: and mouseUp: methods take an NSEvent object as an argument with information about the clicks, including the clickCount.

问题回答

The problem with plain clickCount solution is that double click is considered simply as two single clicks. I mean you still get the single click. And if you want to react differently to that single click, you need something on top of mere click counting. Here s what I ve ended up with (in Swift):

private var _doubleClickTimer: NSTimer?

// a way to ignore first click when listening for double click
override func mouseDown(theEvent: NSEvent) {
    if theEvent.clickCount > 1 {
        _doubleClickTimer!.invalidate()
        onDoubleClick(theEvent)
    } else if theEvent.clickCount == 1 { // can be 0 - if delay was big between down and up
        _doubleClickTimer = NSTimer.scheduledTimerWithTimeInterval(
            0.3, // NSEvent.doubleClickInterval() - too long
            target: self,
            selector: "onDoubleClickTimeout:",
            userInfo: theEvent,
            repeats: false
        )
    }
}


func onDoubleClickTimeout(timer: NSTimer) {
    onClick(timer.userInfo as! NSEvent)
}


func onClick(theEvent: NSEvent) {
    println("single")
}


func onDoubleClick(theEvent: NSEvent) {
    println("double")
}

Generally applications look at clickCount == 2 on -[mouseUp:] to determine a double-click.

One refinement is to keep track of the location of the mouse click on the -[mouseDown:] and see that the delta on the mouse up location is small (5 points or less in both the x and the y).

The NSEvents generated for mouseDown: and mouseUp: have a property called clickCount. Check if it s two to determine if a double click has occurred.

Sample implementation:

- (void)mouseDown:(NSEvent *)event {
    if (event.clickCount == 2) {
        NSLog(@"Double click!");
    }
}

Just place that in your NSResponder (such as an NSView) subclass.

An alternative to the mouseDown: + NSTimer method that I prefer is NSClickGestureRecognizer.

    let doubleClickGestureRecognizer = NSClickGestureRecognizer(target: self, action: #selector(self.myCustomMethod))
    doubleClickGestureRecognizer.numberOfClicksRequired = 2

    self.myView.addGestureRecognizer(doubleClickGestureRecognizer)

I implemented something similar to @jayarjo except this is a bit more modular in that you could use it for any NSView or a subclass of it. This is a custom gesture recognizer that will recognize both click and double actions but not single clicks until the double click threshold has passed:

//
//  DoubleClickGestureRecognizer.swift
//

import Foundation
/// gesture recognizer to detect two clicks and one click without having a massive delay or having to implement all this annoying `requireFailureOf` boilerplate code
final class DoubleClickGestureRecognizer: NSClickGestureRecognizer {

    private let _action: Selector
    private let _doubleAction: Selector
    private var _clickCount: Int = 0

    override var action: Selector? {
        get {
            return nil /// prevent base class from performing any actions
        } set {
            if newValue != nil { // if they are trying to assign an actual action
                fatalError("Only use init(target:action:doubleAction) for assigning actions")
            }
        }
    }

    required init(target: AnyObject, action: Selector, doubleAction: Selector) {
        _action = action
        _doubleAction = doubleAction
        super.init(target: target, action: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(target:action:doubleAction) is only support atm")
    }

    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        _clickCount += 1
        let delayThreshold = 0.15 // fine tune this as needed
        perform(#selector(_resetAndPerformActionIfNecessary), with: nil, afterDelay: delayThreshold)        
        if _clickCount == 2 {
            _ = target?.perform(_doubleAction)
        }
    }

    @objc private func _resetAndPerformActionIfNecessary() {
        if _clickCount == 1 {
            _ = target?.perform(_action)
        }
        _clickCount = 0
    }
}

USAGE :

let gesture = DoubleClickGestureRecognizer(target: self, action: #selector(mySingleAction), doubleAction: #selector(myDoubleAction))
button.addGestureRecognizer(gesture)

@objc func mySingleAction() {
 //  ... single click handling code here
}

@objc func myDoubleAction() {
 // ... double click handling code here
 }

Personally, I check the double click into mouseUp functions:

- (void)mouseUp:(NSEvent *)theEvent
{

    if ([theEvent clickCount] == 2)
    {

        CGPoint point = [theEvent locationInWindow];
        NSLog(@"Double click on: %f, %f", point.x, point.y);

     }

}




相关问题
2 mysql instances in MAC

i recently switched to mac. first and foremost i installed xampp. then for django-python-mysql connectivity, i "somehow" ended up installing a seperate MySQL. now the seperate mysql installation is ...

Iterating over string/strlen with umlauted characters

This is a follow-up to my previous question . I succeeded in implementing the algorithm for checking umlauted characters. The next problem comes from iterating over all characters in a string. I do ...

Controlling OSX windows

I m trying to control windows of a foreign OSX applications from my application. I d like to 1. move the windows on the screen 2. resize the windows on the screen 3. change the currently active window ...

Switching J2SE versions on Mac OS (SnowLeopard)

My current JDK on Mac OS (10.6) is set to 1.6 and I d like to switch to 1.5. A listing of /System/Library/Frameworks/JavaVM.framework/Versions/ shows: lrwxr-xr-x 1 root wheel 10 Nov 3 18:34 ...

Scrolling inside Vim in Mac s Terminal

I ve been googling around trying to figure out if it s possible to use my mouse wheel to scroll while inside Vim in Mac s Terminal, with no luck. It seems as if only X11 or iTerm support this. Before ...

export to MP3 from quicktime API

A question for Apple,QT programmers. Would like to know if it s possible to export a Movie object to MP3 using the QuickTime API. Preferably the ConvertMovieToFile function. I ve looked at ...

热门标签