我建立了一個測試項目像你這樣的,有NSButton
S作爲view
的菜單項,看見你看到相同的行爲。這確實很有趣。如果您子類NSApplication
並覆蓋其-sendEvent:
方法,添加一個日誌以查看哪些事件通過該機制,您會發現-sendEvent:
實際上從未實際調用,當您單擊任何菜單項時,即使是做的都可以工作。這不奇怪嗎?因此接下來要嘗試的是子類NSButton
,爲-mouseDown:
添加覆蓋,並在那裏放置一個斷點。果斷的是,打開子菜單的項目決不會觸發斷點,但其他項目會觸發斷點。而當我們這樣做,回溯是:
(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
正如你所看到的,活動未通過可可事件調度機制,因爲菜單實際上是碳出動。沒錯,許多那些據稱在64位轉換中被刪除的Carbon API和子系統實際上仍然非常活躍,他們現在只是私人API。 我們不能在64位模式下使用它們,但Apple肯定可以,而整個菜單系統仍然是在Carbon事件模型的基礎上實現的。因爲第三方開發人員必須從頭開始重寫Photoshop,這是可以的,但有人在1997年編寫的菜單處理代碼太貴了,不能放棄,我相信你也同意。
無論如何,我在這個backtrace(最頂層的東西除外)中調用了-[NSCarbonWindow sendEvent:]
這個最早的Objective-C方法做了一些測試,看看它是否在子菜單項被點擊時被調用,而不是。所以如果我不得不猜測,我會說問題在於碳事件處理程序。好吧,這可能會在後端造成一點痛苦,但是,嘿,沒問題!我們可以通過下降到Carbon級別並安裝我們自己的Carbon事件處理程序來解決此問題。好吧,捲起你的袖子,讓我們來做 -
哦,對。
我們不能在64位模式下使用這些API。
反正我黯然不認爲有將是一種方式來獲得這個工作短期使用討厭的黑客使用的是什麼,現在私人API,如this guy did和冒着將來破損的(更不用提從App Store中inst)而過)。或者做些什麼確實是瘋狂就像monkepatching其中一個C功能的回溯,這可能會更糟糕。不過,這整個問題確實值得雷達報告。請file one with Apple並讓他們知道這個問題,也許他們會在將來的版本中修復它。
編輯:實際上有一種解決方案,有點。由於附加到沒有子菜單的菜單項的視圖確實會收到您所期望的鼠標事件,因此您可以放棄設置submenu
,並讓您的視圖捕獲mouseEntered:
和mouseExited:
事件並自行顯示菜單,從而模擬子菜單。不是世界上最理想的解決方案,但至少是這樣。
您可以發佈添加菜單項時的代碼嗎?從你的圖片看來,你正在向菜單項添加一個視圖(頂部),而不是將菜單項設置爲自定義視圖。這似乎是一個有趣的問題。 – Farini