根据点击位置丢弃 NSWindow 上的鼠标事件

Posted

技术标签:

【中文标题】根据点击位置丢弃 NSWindow 上的鼠标事件【英文标题】:Discard mouse events on NSWindow based on click position 【发布时间】:2014-03-13 21:02:36 【问题描述】:

假设我有一个浮动的、无边界的圆形NSWindow

它是圆形的,因为内容视图只是画了一个红色的圆圈。

该内容视图需要有图层支持 ([contentView setWantsLayer:YES]),因为我正在对其应用 CoreAnimations,例如动画缩放。

通常,NSWindow 的可点击区域由内容视图的像素透明度定义。然而,不幸的是,一旦 NSWindow 的内容视图变为 layer-backed,透明区域也会收到点击。

就我而言,这是一个严重的问题,因为我只想接收半径范围内的点击。但是现在,在窗口的矩形内点击,但超出圆半径,将激活窗口(因此,整个应用程序),这是不应该的。窗口也可以通过其内容视图的一角拖动。

我最初的想法是在子类中实现[NSWindow sendEvent:],并使用[theEvent locationInWindow]检查是否在半径内执行了点击。我想我可以简单地丢弃该事件,如果它超出了半径,然后不调用[super sendEvent:theEvent]。然而这并没有奏效:我注意到,mouseDown:; window 方法甚至在 sendEvent 之前被调用:;方法。

我搜索了很多,但我发现的唯一想法是在窗口顶部有一个类似非层支持的 NSWindow 的代理,它有条件地委托点击,但这会导致不可预测的 UI 行为。

你们有什么想法,如何解决?

【问题讨论】:

您是否尝试过通过继承NSApplication 并实现-sendEvent: 覆盖在应用程序级别拦截事件? 我刚刚测试过,没有成功。即使我尝试通过在 NSApplication 子类中从不调用 [super sendEvent:] 来丢弃 any 事件,窗口仍然可以通过鼠标拖动来移动。此外,覆盖 [NSApplication postEvent:] 也不起作用。 【参考方案1】:

如果你想根据位置丢弃 mouseDown 事件,你可以使用:

CGPathContainsPoint(path,transform,point,eoFill):Bool

设置您的路径以匹配您的图形。圆形、椭圆形、矩形、三角形或路径,甚至组合路径(其中有孔的路径)。

【讨论】:

然后呢?在这种情况下,可以覆盖 hitTest() 以返回 nil ,但这似乎不会将点击发送到下一个窗口.. 覆盖 hitTest 方法并在 hitTest 方法中处理您的代码。如果 mouseDown 点在路径之外,则使用 super 转发 hitTest 事件。 这是一个运行良好的版本,使用了遮罩层:github.com/aphofstede/TransparentWindowClickthroughTest/tree/… 我猜这与出现在窗口边缘的调整大小手柄有关。苹果提供的调整大小的解决方案适用于矩形窗口。所以他们可能决定在窗口不是矩形的情况下打破透明点击。您正在尝试的开创性工作。 我通过使用 NSEvent.addLocalMonitorForEventsMatchingMask 和 NSEvent.removeMonitor 的组合实现了一次自定义窗口大小调整。它应该可以解决问题。一些肘部润滑脂可能适用;)【参考方案2】:

所以几周后,我得出了以下结果:

A) 代理窗口: 使用非层支持的代理窗口,它作为子窗口放置在目标窗口的顶部。代理窗口与目标窗口具有相同的形状,并且由于它不是图层支持的,因此它将正确接收和忽略事件。代理窗口通过覆盖sendEvent: 将所有事件委托给目标窗口。目标窗口设置为忽略所有鼠标事件。

B) 全局鼠标指针观察: 使用addGlobalMonitorForEventsMatchingMaskaddLocalMonitorForEventsMatchingMaskNSMouseMovedMask|NSLeftMouseDraggedMask 事件安装全局和本地事件监视器。事件监视器根据当前全局鼠标位置禁用和启用忽略所有已注册目标窗口上的鼠标事件。在圆形窗口的情况下,必须计算鼠标指针到每个目标窗口的距离。

这两种方法通常都运行良好,但我遇到了一些子窗口方法的不可预知的不当行为(子窗口与其父窗口的位置“不同步”)。

更新:这两种方法都有一些明显的缺点: 在 A) 中,代理窗口有时可能会不同步,并且可能会稍微偏离实际窗口。

在 B) 中,事件监视器在移动鼠标时对电池寿命有很大影响,即使应用程序不是最前面的应用程序也是如此。

【讨论】:

请查看***.com/questions/29441015/…

以上是关于根据点击位置丢弃 NSWindow 上的鼠标事件的主要内容,如果未能解决你的问题,请参考以下文章

如何根据鼠标点击位置参数触发Javascript中的事件?

如何正确响应ArcGIS JavaScript API中图形的鼠标事件

键盘的事件被认为是鼠标在 GUI 上的点击

鼠标右击事件

可拖动的 NSWindow 闪烁

为啥我的 NSWindow 第一次只接收 mouseOver 事件?