2014-11-14 6 views
9

Ich schreibe eine einfache Statusleiste App in Swift, und versuchen, die neue NSStatusItem API in OS X 10.10 eingeführt.Swift: NSStatusItem Menü Verhalten in 10.10 (z. B. nur mit der rechten Maustaste zeigen)

Die Schnittstelle, auf die ich ziele, ist ein einfacher linker Mausklick auf das statusItem, um eine Kernfunktion ein- und auszuschalten, mit einem rechten Mausklick (oder Control-Klick), um ein Einstellungsmenü anzuzeigen. Ich brauche keine benutzerdefinierte Ansicht oder Popover für diese Funktionalität.

Wenn ein NSMenu einem NSStatusItem zugewiesen ist, wird standardmäßig das Menü sowohl mit Linksklick als auch mit Rechtsklick angezeigt. Ich möchte das Verhalten ändern, um nur das Menü auf einen Rechtsklick zu zeigen, oder als eine Umgehungsmöglichkeit, das Menü bei einem Linksklick zu öffnen

Bisher scheint es, dass die Steuerung von Mausereignissen auf einem NSStatusItem, eins musste eine benutzerdefinierte Ansicht mit überschriebenen Mausereignissen einstellen (siehe this related question).

Im neuen NSStatusItem API, das in 10.10 eingeführt wurde, sind Methoden zum Festlegen einer benutzerdefinierten Ansicht veraltet, und es sieht nicht danach aus, als ob von diesem Verhalten abgeraten wird. Laut @ Taylor in this answer sollten einige der veralteten Verhaltensweisen über das NSStatusBarButton-Objekt verwendet werden, das von statusItemObject.button() zurückgegeben wird, aber zum Schreiben gibt es keine Dokumentation für NSStatusBarButton, und das zurückgegebene Objekt ist schreibgeschützt und kann nicht durch ersetzt werden eine benutzerdefinierte Schaltfläche mit überschriebenen Mausereignishandlern.

Gibt es eine Möglichkeit, ein gewisses Maß an Kontrolle darüber zu erlangen, ob ein NSMenu, das an ein NSStatusItem (oder ein NSStatusBarButton) angehängt ist, in Bezug auf Mausereignisse angezeigt wird?

Antwort

5

Hier ist die Lösung kam ich mit. Es funktioniert ziemlich gut, obwohl es eine Sache gibt, mit der ich nicht zufrieden bin: Das Statuselement bleibt markiert, nachdem Sie im Kontextmenü eine Option ausgewählt haben. Das Highlight verschwindet, sobald Sie mit etwas anderem interagieren.

Beachten Sie auch, dass popUpStatusItemMenu: ab OS X 10.10 (Yosemite) "soft deprecated" ist und in einer zukünftigen Version nicht mehr verwendet wird. Für den Moment funktioniert es und wird Sie nicht warnen. Hoffentlich haben wir einen vollständig unterstützten Weg, dies zu tun, bevor es offiziell veraltet ist - ich würde filing a bug report empfehlen, wenn Sie zustimmen.

Zuerst müssen Sie ein paar Eigenschaften und eine ENUM:

typedef NS_ENUM(NSUInteger,JUNStatusItemActionType) { 
    JUNStatusItemActionNone, 
    JUNStatusItemActionPrimary, 
    JUNStatusItemActionSecondary 
}; 

@property (nonatomic, strong) NSStatusItem *statusItem; 
@property (nonatomic, strong) NSMenu *statusItemMenu; 
@property (nonatomic) JUNStatusItemActionType statusItemAction; 

Dann irgendwann werden Sie den Status Punkt einrichten möchten:

NSStatusItem *item = [[NSStatusBar systemStatusBar] statusItemWithLength:29.0]; 
NSStatusBarButton *button = item.button; 
button.image = [NSImage imageNamed:@"Menu-Icon"]; 
button.target = self; 
button.action = @selector(handleStatusItemAction:); 
[button sendActionOn:(NSLeftMouseDownMask|NSRightMouseDownMask|NSLeftMouseUpMask|NSRightMouseUpMask)]; 
self.statusItem = item; 

Dann einfach Sie müssen behandeln die Aktionen durch den Status Artikel Taste gesendet:

- (void)handleStatusItemAction:(id)sender { 

    const NSUInteger buttonMask = [NSEvent pressedMouseButtons]; 
    BOOL primaryDown = ((buttonMask & (1 << 0)) != 0); 
    BOOL secondaryDown = ((buttonMask & (1 << 1)) != 0); 
    // Treat a control-click as a secondary click 
    if (primaryDown && ([NSEvent modifierFlags] & NSControlKeyMask)) { 
     primaryDown = NO; 
     secondaryDown = YES; 
    } 

    if (primaryDown) { 
     self.statusItemAction = JUNStatusItemActionPrimary; 
    } else if (secondaryDown) { 
     self.statusItemAction = JUNStatusItemActionSecondary; 
     if (self.statusItemMenu == nil) { 
      NSMenu *menu = [[NSMenu alloc] initWithTitle:@""]; 
      [menu addItemWithTitle:NSLocalizedString(@"Quit",nil) action:@selector(terminate:) keyEquivalent:@""]; 
      self.statusItemMenu = menu; 
     } 
     [self.statusItem popUpStatusItemMenu:self.statusItemMenu]; 
    } else { 
     self.statusItemAction = JUNStatusItemActionNone; 
     if (self.statusItemAction == JUNStatusItemActionPrimary) { 
      // TODO: add whatever you like for the primary action here 
     } 
    } 

} 

Also im Grunde handleStatusItemAction: genannt wird mit der Maus nach unten und mit der Maus nach oben für beide Maustasten.Wenn eine Schaltfläche inaktiv ist, wird protokolliert, ob die primäre oder sekundäre Aktion ausgeführt werden soll. Wenn es sich um eine sekundäre Aktion handelt, wird diese sofort behandelt, da Menüs normalerweise mit der Maustaste angezeigt werden. Wenn es sich um eine primäre Aktion handelt, wird dies mit der Maus erledigt.

+1

Ein paar Notizen (die folgenden Schnipsel sind in Swift): a) Sie können die nach einem Rechtsklick verbleibende Hervorhebung lösen, indem Sie 'item.highlightMode = false' für das StatusItem-Objekt setzen. b) Der Fall für die primäre Aktion sollte zuerst im letzten Else-Block (vor 'self.statusItemAction = JUNStatusItemActionNone;') für das gewünschte Verhalten kommen. Andernfalls setzen Sie den Wert von 'self.statusItemAction' und prüfen sofort, ob es etwas anderes ist. – AmusedToDeath

0

Dies ist in 10.10 veraltet, wird aber weiterhin funktionieren:

[self.statusItem setTarget:self]; // Otherwise this goes to the first responder 
[self.statusItem setAction:@selector(statusItemClicked:)]; 
[self.statusItem sendActionOn:(NSRightMouseUpMask)]; 

Sie andere Veranstaltungen in setActionOn von bitmasking sie einstellen können. So zum Beispiel, wenn Sie nach links und rechts klicken wanted:

[self.statusItem sendActionOn:(NSLeftMouseUpMask | NSRightMouseUpMask)]; 

(Entschuldigen Sie die ObjC, sollten Sie in der Lage sein, es in geschickter zu übersetzen und es sollte funktionieren)

Verwandte Themen