NSMenuItem mit der benutzerdefinierten Ansicht empfängt keine Mausereignisse

8

Ich arbeite an einer Menüleisten-App und setze eine benutzerdefinierte Ansicht mit NSMenuItem 's view -Eigenschaft.

Die Ansicht wird zwar angezeigt, aber ich kann keine Mausklickereignisse für Menüelemente mit geöffneten Untermenüs empfangen.

In diesem Screenshot habe ich jedem Gegenstand eine Schaltfläche hinzugefügt. Die 3 Tasten rechts oben funktionieren korrekt, aber die in den übergeordneten Menüs erhalten überhaupt keine Klickereignisse.

Ich habe einiges ausprobiert, einschließlich:

  • Der Versuch, Mausereignisse mit den Methoden mouseUp und mouseDown
  • zu erfassen
  • Die NSWindow für den benutzerdefinierten Ansichtsschlüssel erstellen, wenn die Maus diese Ansicht aufruft
  • Hinzufügen von globalen und lokalen Monitoren für NSEvents

... aber ohne Erfolg

Auch ohne den Ansatz, eine Schaltfläche hinzuzufügen, kann ich das Standardverhalten eines Standard NSMenuItem nicht replizieren, da der target-action Callback für NSMenuItem nicht aufgerufen wird, wenn er eine benutzerdefinierte Ansicht hat. (und ich kann keine Klickereignisse erhalten, um es selbst aufzurufen)

Theoretisch sollte dies möglich sein, weil ich Menüs mit offenen Untermenüs mit dem Standard NSMenuItem (keine benutzerdefinierte Ansicht) auswählen kann.

Kann jemand helfen?

Danke

    
SteveB 13.06.2017, 17:18
quelle

1 Antwort

4

Ich habe ein Testprojekt wie das Ihre eingerichtet, mit NSButton s als view für die Menüelemente und das gleiche Verhalten, das Sie gesehen haben. Es ist in der Tat faszinierend. Wenn Sie NSApplication ableiten und die Methode -sendEvent: überschreiben, fügen Sie ein Protokoll hinzu, um zu sehen, welche Ereignisse den Mechanismus durchlaufen. Sie werden feststellen, dass -sendEvent: niemals tatsächlich aufgerufen wird, wenn Sie auf eines der Menüelemente klicken funktioniert . Ist das nicht komisch? Das nächste, was versucht wird, ist, die Klasse NSButton zu untergliedern, eine Überschreibung für -mouseDown: hinzuzufügen und dort einen Haltepunkt zu setzen. Tatsächlich wird der Haltepunkt für das Element mit dem geöffneten Untermenü nie getroffen, aber für die anderen wird er getroffen. Und wenn wir das tun, ist das Backtrace:

%Vor%

Wie Sie sehen, werden die Ereignisse nicht durch den Cocoa Event Dispatch Mechanismus ausgelöst, da die Menüs tatsächlich Carbon sind. Das stimmt, viele dieser Carbon APIs und Subsysteme, die angeblich in der Übergang zu 64-Bit sind tatsächlich noch ziemlich lebendig und gut; Sie sind jetzt nur private API. Wir können sie nicht im 64-Bit-Modus verwenden, aber Apple kann das, und das gesamte Menüsystem wird immer noch auf dem Carbon-Ereignismodell implementiert. Weil es für Entwickler von Drittanbietern in Ordnung ist, Photoshop neu schreiben zu müssen, aber das Menü, das Code verarbeitet, den jemand 1997 geschrieben hat, ist viel zu wertvoll, um einfach aufzugeben. Ich bin mir sicher, dass Sie mir zustimmen.

Wie auch immer, ich habe einen kleinen Test gemacht, indem ich -[NSCarbonWindow sendEvent:] , die früheste Objective-C-Methode in diesem Backtrace (abgesehen von den Toplevel-Sachen), umspritze, um zu sehen, ob sie überhaupt aufgerufen wurde, als der Untermenüpunkt war geklickt, und es ist nicht. Wenn ich also raten müsste, würde ich sagen, dass das Problem im Carbon Event Handler liegt. Nun, das ist vielleicht ein bisschen ein Schmerz im hinteren Teil, aber hey, kein Problem! Wir können dies umgehen, indem wir auf die Carbon-Ebene herunterfahren und unseren eigenen Carbon Event-Handler installieren. Alles klar, die Ärmel hochkrempeln, lass uns das tun -

Oh, richtig.

Diese APIs können nicht im 64-Bit-Modus verwendet werden.

Wie auch immer, ich glaube leider nicht, dass es einen Weg geben wird, dies zu schaffen, um nicht fiese Hacks zu benutzen, um private APIs wie Dieser Typ hat und riskiert zukünftigen Bruch (ganz zu schweigen von instabanned aus dem App Store). Oder etwas tun, das wirklich verrückt ist, wie man eine dieser C-Funktionen im Backtrace anpasst, was wahrscheinlich noch schlimmer wird. Diese ganze Ausgabe scheint jedoch einem Radarbericht würdig zu sein. Bitte eins mit Apple und sie über dieses Problem informieren, und vielleicht werden sie es in einer zukünftigen Version reparieren.

EDIT: Es gibt tatsächlich eine Lösung, irgendwie. Da eine Ansicht, die mit einem Menüelement verknüpft ist, das kein Untermenü enthält, die erwarteten Mausereignisse erhält, können Sie auf submenu verzichten und Ihre Ansicht nur die Ereignisse mouseEntered: und mouseExited: erfassen lassen und die Menü selbst und simuliert so das Untermenü. Nicht die ideale Lösung auf der Welt, aber es ist zumindest etwas.

    
Charles Srstka 24.09.2017 07:46
quelle