NSView 不接收 mouseUp: 鼠标按钮在视图外释放时的事件
NSView does not receive mouseUp: event when mouse button is released outside of view
我有一个自定义 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
实现没有帮助。
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") }
我将此发布为对我需要知道用户已停止使用滑块的类似问题的回答。我需要从 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
//...
我有一个自定义 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
实现没有帮助。
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") }
我将此发布为对我需要知道用户已停止使用滑块的类似问题的回答。我需要从 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
//...