2017-06-13 88 views
8

我正在使用菜單欄應用程序,並使用NSMenuItemview屬性設置自定義視圖。帶自定義視圖的NSMenuItem不會收到鼠標事件

該視圖顯示正常,但我無法接收任何種類的鼠標點擊事件,菜單項具有打開的子菜單。

在此屏幕截圖中,我爲每個項目添加了一個按鈕。最右邊的3個按鈕功能正常,但父菜單中的按鈕根本不會收到任何點擊事件。

Screenshot

我已經嘗試了一堆東西,其中包括:

  • 嘗試使用mouseUpmouseDown方法
  • 使得NSWindow自定義視圖鍵拍攝鼠標事件時鼠標進入該視圖
  • 添加全局和本地顯示器NSEvents

...但無濟於事

即使沒有添加按鈕的方法,我不能複製的標準NSMenuItem默認行爲,爲target-action回調的NSMenuItem不會被調用,如果它有一個自定義的視圖。 (我不能接收任何點擊事件來自己調用它)

理論上這應該是可能的,因爲我可以選擇使用默認NSMenuItem(無自定義視圖)打開子菜單的菜單。

有人能幫忙嗎?

感謝

+2

您可以發佈添加菜單項時的代碼嗎?從你的圖片看來,你正在向菜單項添加一個視圖(頂部),而不是將菜單項設置爲自定義視圖。這似乎是一個有趣的問題。 – Farini

回答

4

我建立了一個測試項目像你這樣的,有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。

Picard Facepalm

反正我黯然不認爲有將是一種方式來獲得這個工作短期使用討厭的黑客使用的是什麼,現在私人API,如this guy did和冒着將來破損的(更不用提從App Store中inst)而過)。或者做些什麼確實是瘋狂就像monkepatching其中一個C功能的回溯,這可能會更糟糕。不過,這整個問題確實值得雷達報告。請file one with Apple並讓他們知道這個問題,也許他們會在將來的版本中修復它。

編輯:實際上有一種解決方案,有點。由於附加到沒有子菜單的菜單項的視圖確實會收到您所期望的鼠標事件,因此您可以放棄設置submenu,並讓您的視圖捕獲mouseEntered:mouseExited:事件並自行顯示菜單,從而模擬子菜單。不是世界上最理想的解決方案,但至少是這樣。

相關問題