【问题标题】:Catching double click in Cocoa OSX在 Cocoa OSX 中捕获双击
【发布时间】:2018-10-01 16:43:34
【问题描述】:

NSResponder 似乎没有鼠标双击事件。有没有简单的方法来捕捉双击?

【问题讨论】:

    标签: cocoa macos double-click nsresponder


    【解决方案1】:

    mouseDown:mouseUp: 方法将 NSEvent 对象作为参数,其中包含有关点击的信息,包括 clickCount

    【讨论】:

    • 成功了。但我们应该考虑到它破坏了几个组件的选择流程 - 例如 NSTextView。
    【解决方案2】:

    普通clickCount 解决方案的问题是双击被简单地视为两次单击。我的意思是你仍然可以单击。如果您想对单次点击做出不同的反应,您需要在单纯的点击计数之上做一些事情。这是我最终得到的结果(在 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")
    }
    

    【讨论】:

      【解决方案3】:

      通常应用程序会查看 -[mouseUp:] 上的 clickCount == 2 来确定双击。

      一种改进是跟踪鼠标在 -[mouseDown:] 上单击的位置,并查看鼠标向上位置上的增量很小(x 和 y 均小于等于 5 点)。

      【讨论】:

      • 恕我直言,这是最有用的答案,因为它还回答了是否对第二个 mouseDown 或第二个 mouseUp 做出反应的隐含问题。当然,在某些情况下,偏离标准可能是有意义的。不幸的是,Apple 自己并不完全遵守一个标准(Finder 和 Mail 向上,Calendar 向下)......
      【解决方案4】:

      mouseDown:mouseUp: 生成的NSEvents 有一个名为clickCount 的属性。检查是否为二,判断是否发生了双击。

      示例实现:

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

      只需将其放在您的 NSResponder(例如 NSView)子类中即可。

      【讨论】:

      • 如果你需要同时处理这两种情况,你通常会怎么做——单击和双击。显然,如果最终结果是双击,您将不得不以某种方式忽略单击?
      • @jayarjo - 在我的脑海中,如果事实证明双击是必要的,我想不出任何不应该通过单击完成的操作的地方。在文本字段中,单击即可将光标置于特定位置。双击突出显示整个单词。因此,单击移动光标是无害的。在 RTS 游戏中(至少是暴雪的),单击选择一个单位,而双击选择该类型的所有单位。如果您希望双击执行与单击完全不同的操作,您可能需要重新考虑您的整个用户体验。
      【解决方案5】:

      我更喜欢mouseDown: + NSTimer 方法的替代方法是NSClickGestureRecognizer

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

      【讨论】:

      • 这显示了与 mouseDown 一样的确切示例问题:如果您有两个用于单击和双击的手势识别器,则在双击的情况下也会调用单击选择器
      • 这对于这个问题来说太过分了,而且不是正确的方法。 Chuck 的解决方法是正确的:在 -mouseUp: 或 -mouseDown: 中获取 NSEvent 的 clickCount:
      【解决方案6】:

      我实现了类似于@jayarjo 的东西,只是它更加模块化,因为您可以将它用于任何 NSView 或其子类。这是一个自定义手势识别器,它将识别单击和双击动作,但在超过双击阈值之前不能识别单击:

      //
      //  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
          }
      }
      

      用法:

      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
       }
      

      【讨论】:

        【解决方案7】:

        就我个人而言,我检查了鼠标双击功能:

        - (void)mouseUp:(NSEvent *)theEvent
        {
        
            if ([theEvent clickCount] == 2)
            {
        
                CGPoint point = [theEvent locationInWindow];
                NSLog(@"Double click on: %f, %f", point.x, point.y);
        
             }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多