首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有自定义视图的NSMenuItem不接收鼠标事件

具有自定义视图的NSMenuItem不接收鼠标事件
EN

Stack Overflow用户
提问于 2017-06-13 17:18:40
回答 1查看 1.3K关注 0票数 11

我正在开发一个菜单栏应用程序,我正在使用NSMenuItemview属性设置一个自定义视图。

该视图显示“确定”,但对于打开的子菜单,我无法接收任何类型的鼠标单击事件。

在这个截图中,我给每个项目添加了一个按钮。三个最右边的按钮功能正常,但是父菜单中的按钮根本没有接收到任何点击事件。

我试过很多东西,包括:

  • 尝试使用mouseUpmouseDown方法捕获鼠标事件
  • 当鼠标进入自定义视图键时,为该视图创建NSWindow
  • NSEvents添加全局和本地监视器

...but无效

即使没有添加按钮的方法,我也无法复制标准NSMenuItem的默认行为,因为如果NSMenuItem具有自定义视图,则不会调用NSMenuItemtarget-action回调。(我无法接收到任何点击事件来调用它)

理论上,这应该是可能的,因为我可以使用默认的NSMenuItem (没有自定义视图)选择具有打开子菜单的菜单。

有人能帮忙吗?

谢谢

EN

回答 1

Stack Overflow用户

发布于 2017-09-24 07:46:20

我设置了一个像您这样的测试项目,以NSButtons作为菜单项的view,并看到了您所看到的相同行为。这确实令人感兴趣。如果子类NSApplication并重写其-sendEvent:方法,添加日志以查看通过该机制发生的事件,则您会发现在单击任何菜单项,甚至是实际工作的菜单项时,都不会实际调用-sendEvent:。这不奇怪吗?接下来要尝试的是子类NSButton,为-mouseDown:添加一个覆盖,并在那里放置一个断点。当然,对于打开的子菜单,断点永远不会被击中,但是对于其他的子菜单,它会被击中。当我们这么做的时候,回溯是:

代码语言:javascript
复制
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000100002fa0 menutest`MyButton.mouseDown(event=0x0000608000121900, self=0x0000600000140a50) at AppDelegate.swift:33
    frame #1: 0x000000010000303c menutest`@objc MyButton.mouseDown(with:) at AppDelegate.swift:0
    frame #2: 0x00007fffa9f6724f AppKit`-[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 6341
    frame #3: 0x00007fffa9f63a6c AppKit`-[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 1942
    frame #4: 0x00007fffa9f62f0a AppKit`-[NSWindow(NSEventRouting) sendEvent:] + 541
    frame #5: 0x00007fffa9a2328d AppKit`-[NSCarbonWindow sendEvent:] + 118
    frame #6: 0x00007fffa9a20261 AppKit`NSMenuItemCarbonEventHandler + 10597
    frame #7: 0x00007fffab0acd85 HIToolbox`DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1708
    frame #8: 0x00007fffab0abff6 HIToolbox`SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 428
    frame #9: 0x00007fffab0c1d14 HIToolbox`SendEventToEventTarget + 40
    frame #10: 0x00007fffab0ea7df HIToolbox`ToolboxEventDispatcherHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) + 2503
    frame #11: 0x00007fffab0ad17a HIToolbox`DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 2721
    frame #12: 0x00007fffab0abff6 HIToolbox`SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 428
    frame #13: 0x00007fffab0c1d14 HIToolbox`SendEventToEventTarget + 40
    frame #14: 0x00007fffab12e928 HIToolbox`IsUserStillTracking(MenuSelectData*, unsigned char*) + 1658
    frame #15: 0x00007fffab255dc4 HIToolbox`TrackMenuCommon(MenuSelectData&, unsigned char*, SelectionData*, MenuResult*, MenuResult*) + 1664
    frame #16: 0x00007fffab13a223 HIToolbox`MenuSelectCore(MenuData*, Point, double, unsigned int, OpaqueMenuRef**, unsigned short*) + 554
    frame #17: 0x00007fffab139f66 HIToolbox`_HandleMenuSelection2 + 460
    frame #18: 0x00007fffa97ee368 AppKit`_NSHandleCarbonMenuEvent + 239
    frame #19: 0x00007fffa9a68702 AppKit`_DPSEventHandledByCarbon + 54
    frame #20: 0x00007fffa9de90c5 AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 963
    frame #21: 0x00007fffa96623db AppKit`-[NSApplication run] + 926
    frame #22: 0x00007fffa962ce0e AppKit`NSApplicationMain + 1237
    frame #23: 0x00000001000035fd menutest`main at AppDelegate.swift:13
    frame #24: 0x00007fffc12fc235 libdyld.dylib`start + 1

如您所见,这些事件并不是通过Cocoa事件分派机制分派的,因为菜单实际上是碳元素。没错,许多在64位转换过程中被删除的碳API和子系统实际上仍然很活跃,而且很好;它们现在只是私有的API。我们不能在64位模式下使用它们,但苹果当然可以,整个菜单系统仍然是在碳事件模型之上实现的。因为第三方开发者可以从头开始重写Photoshop,但是有人在1997年编写的菜单处理代码太有价值了,我相信你也同意。

无论如何,我做了一个小小的测试,用-[NSCarbonWindow sendEvent:] (回溯中最早的目标C方法)(除了最高级的东西),看看它是否在单击子菜单时被调用,而不是。因此,如果我不得不猜测,我会说问题在于碳事件处理程序。嗯,这可能是有点痛苦的后端,但嘿,没有问题!我们可以通过下降到碳水平并安装我们自己的碳事件处理程序来解决这个问题。好吧,卷起你的袖子,让我们做-

哦,对了。

我们不能在64位模式下使用这些API。

无论如何,我很遗憾,我不认为有什么办法可以让这件事发挥作用,除非使用讨厌的黑客来使用现在是私有的App,比如这家伙做了,并冒着将来的破坏风险(更别提是从App安装的)。或者做一些疯狂的事情,比如在回溯中设置一个C函数,这可能会更糟。不过,整个问题确实值得一份雷达报告。请与苹果一起归档并让他们知道这个问题,也许他们会在将来的某个版本中解决这个问题。

编辑:实际上有一个解决方案,有点。由于附加到一个没有子菜单的菜单项上的视图确实收到了您期望的鼠标事件,所以您可以放弃设置submenu,让视图捕获mouseEntered:mouseExited:事件并自己显示菜单,从而模拟子菜单。这不是世界上最理想的解决方案,但至少是有意义的。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44527792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档