在视图外部释放鼠标按钮时,NSView不会收到mouseUp:event

时间:2016-11-22 14:13:54

标签: cocoa event-handling nsview appkit mouseup

我有一个自定义NSView子类(例如)以下方法:

override func mouseDown(with event: NSEvent) { Swift.print("mouseDown") }
override func mouseDragged(with event: NSEvent) { Swift.print("mouseDragged") }
override func mouseUp(with event: NSEvent) { Swift.print("mouseUp") }

只要按下鼠标(按钮),拖动并释放所有视图内部​​,这都可以正常工作。但是,当在视图内按下鼠标,移到视图外,然后才释放时,我从未收到mouseUp事件。

P.S。:调用super实现无济于事。

2 个答案:

答案 0 :(得分:7)

Apple的鼠标事件文档的Handling Mouse Dragging Operations部分提供了一个解决方案:显然,我们会在使用鼠标跟踪循环跟踪事件时收到mouseUp事件。

以下是文档中示例代码的变体,适用于Swift 3:

override func mouseDown(with event: NSEvent) {
    var keepOn = true

    mouseDownImpl(with: event)

    // We need to use a mouse-tracking loop as otherwise mouseUp events are not delivered when the mouse button is
    // released outside the view.
    while true {
        guard let nextEvent = self.window?.nextEvent(matching: [.leftMouseUp, .leftMouseDragged]) else { continue }
        let mouseLocation = self.convert(nextEvent.locationInWindow, from: nil)
        let isInside = self.bounds.contains(mouseLocation)

        switch nextEvent.type {
        case .leftMouseDragged:
            if isInside {
                mouseDraggedImpl(with: nextEvent)
            }

        case .leftMouseUp:
            mouseUpImpl(with: nextEvent)
            return

        default: break
        }
    }
}

func mouseDownImpl(with event: NSEvent) { Swift.print("mouseDown") }
func mouseDraggedImpl(with event: NSEvent) { Swift.print("mouseDragged") }
func mouseUpImpl(with event: NSEvent) { Swift.print("mouseUp") }

答案 1 :(得分:0)

将其发布为一个类似问题的答案,我需要知道用户已停止使用滑块。我需要从NSSlider或实际上是NSView捕获mouseUp事件。对我来说,解决方案是简单地捕获mouseDown事件,并在退出时添加一些代码并完成我需要的工作。希望这对需要做类似事情的其他人有用。使用XCode 11.3.1 Swift 5编写的代码

import Cocoa

class SMSlider: NSSlider {

    var calledOnExit:(()->())?

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }

    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        if self.calledOnExit != nil {
            self.calledOnExit!()
        }
    }    
}

// In my main swift app
func sliderStopped() {
    print("Slider stopped moving")
}

//...
if slider == nil {
    slider = SMSlider()
}
slider?.isContinuous = true
slider?.target = self
slider?.calledOnExit = sliderStopped
//...