2014-09-23 10 views
11

A partire da OS X 10.10 la maggior parte di NSStatusItem è stata dichiarata obsoleta a favore della proprietà button, che consiste in un NSStatusBarButton. Dovrebbe funzionare come un normale pulsante, ma sfortunatamente anche i metodi cell e setCell in NSStatusButton sono stati deprecati. Di conseguenza, sto cercando di trovare un modo per mantenere il pulsante evidenziato dopo che è stato cliccato (normalmente il pulsante è evidenziato con il mouse verso il basso e non evidenziato con il mouse verso l'alto. Voglio mantenerlo evidenziato dopo il mouse su).NSStatusBarButton mantenere evidenziato

Chiamare [NSStatusButton setHighlighted:] nella sua azione non funziona perché sembra non essere illuminato da solo una volta che il mouse è attivo. D'altra parte, l'utilizzo di un ritardo per chiamarlo sul ciclo successivo, ovvero [self performSelector: withDelay:], fa lampeggiare l'evidenziatore in modo piuttosto sgradevole. Funziona, ma non sembra carino.

L'impostazione del tipo di pulsante su NSToggleButton rimuove completamente l'evidenziazione e evidenzia l'immagine del modello che era dispari.

Questi erano gli unici metodi che potevo pensare. Esiste comunque la possibilità di ignorare questo comportamento di mouseUp NSButtonCell?

+0

Dove hai letto che 'NSStatusItem' è deprecato? – PnotNP

+0

@NulledPointer https://developer.apple.com/library/prerelease/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSStatusItem_Class/index.html#//apple_ref/doc/uid/TP40004118 – Luke

+3

NSStatusItem non è deprecato, molti dei suoi metodi sono stati deprecati in 10.10. – ctpenrose

risposta

4

ho aggiunto una visualizzazione secondaria per l'elemento dello stato, e dentro quella vista ho aggiunto i gestori di eventi per il mouseDown ecc, che ha chiamato [ [pulsante statusItem] evidenziare: true]. Come risulta setHighlighted: non fa la stessa cosa di highlight :.

NSArray *array = [NSArray arrayWithObjects:[statusItem button], [self statusItemView], nil]; 
[[[statusItem button] superview] setSubviews:array]; 
//Highlight like so: 
[[statusItem button] highlight:true]; 

EDIT: Come di El Capitan questo metodo non funziona più, e nemmeno statusItem.button.highlight = true sia

+0

Trovi che qualcosa funzioni su El Capitan? –

2

TL; DR: Qualsiasi NSButton esempio (con NSImage che ha template=YES) all'interno NSStatusItem proprietà sembra visivamente esattamente come NSStatusBarButton . Puoi controllare la loro proprietà highlight come vuoi.

Se si desidera controllare manualmente l'evidenziazione del proprio NSStatusItem e allo stesso tempo ottenere tutti i vantaggi dell'aspetto dall'uso di NSStatusBarButton, è possibile utilizzare un approccio leggermente diverso. Puoi creare la tua istanza NSButton che ha la sua proprietà highlight completamente sotto il tuo controllo. Quindi devi creare l'istanza NSImage e impostare la proprietà template su YES. Quindi devi aggiungere questo button a [NSStatusItem view] (sì, che è softly deprecated) o anche come sottoview al sistema creato [NSStatusItem button]. Dopo questo devi disegnare lo sfondo di NSStatusItem manualmente con [NSStatusItem drawStatusBarBackgroundInRect:withHighlight:] (che è anche deprecato, oh).

Con questo approccio, è possibile combinare il pieno controllo dell'aspetto del proprio NSStatusItem e ottenere lo styling automatico dell'immagine del pulsante.

+1

Ho passato tutto il giorno a cercare di aggirare la nuova API, ma grazie al tuo commento ho provato la deprecata API 'drawStatusBarBackgroundInRect: withHighlight:' e funziona molto meglio secondo me. Sono abbastanza sicuro che Apple utilizzi ancora l'API obsoleta per le icone delle loro icone di menu, dal momento che l'evidenziazione rimane attiva. Molto strano che Apple avrebbe solo lampeggiare l'evidenziazione nel nuovo 'NSStatusBarButton'. – iMaddin

0

La risposta di Luke è ottima. Sto solo condividendo la mia implementazione basandomi su quello.

NSButton *button = [[NSButton alloc] initWithFrame:self.statusItem.button.frame]; 
button.alphaValue = 0; 
NSArray *array = @[self.statusItem.button, button]; 
self.statusItem.button.superview.subviews = array; 

[button sendActionOn:(NSLeftMouseDownMask | NSRightMouseDownMask)]; 
button.target = self; 
button.action = @selector(statusItemClicked); 
2

Lottando con questo problema me stesso, ho scoperto che sovrascrivere mouseDown: in una categoria sulla NSStatusBarButton opere:

#import "MUTargetClass.h" 

@implementation NSStatusBarButton (Additions) 

- (void)mouseDown:(NSEvent *)theEvent 
{ 
    // Relay CTRL+Click to perform a right click action 
    if(theEvent.modifierFlags & NSControlKeyMask) 
    { 
     [self rightMouseDown:theEvent]; 
     return; 
    } 

    // Handle highlighting 
    [self setHighlighted:YES]; 

    // Perform action on target 
    [(MUTargetClass *)self.target actionSelector:self]; 
} 

@end 

MUTargetClass potrebbe poi per esempio implementare:

#import "NSStatusBarButton+Additions.h" 

@implementation MUTargetClass 

[…] 
    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; 
    NSStatusBarButton *button = [self.statusItem button]; 
    [button setTarget:self]; 
[…] 

- (void)actionSelector:(id)sender 
{ 
    // Whatever behavior a click on the button should invoke 
} 

[…] 
    // Reset button's highlighting status when done 
    [[self.statusItem button] setHighlighted:NO]; 
[…] 

@end 

Nota che la funzionalità di CTRL + facendo clic sul pulsante si sta perdendo nell'override mouseDown:. Come mostrato sopra, può essere ripristinato inoltrando l'evento a rightMouseDown:.

Un modo più semplice di avere l'azione chiamata sarebbe qualcosa sulla falsariga di [self.target performSelector:self.action] nella categoria e [self.statusItem setAction:@selector(actionSelector:)] nella classe di destinazione, tuttavia questo may cause a leak in progetti ARC.

Modifica: funziona anche su El Capitan.

+0

@xhacker: testato su OS X 10.11. –

0

Se si pianifica l'evidenziazione del pulsante per un'esecuzione successiva sul thread principale, tutto sembra funzionare. Funziona anche su El Capitan.

if self.appPopover.shown { 
     self.appPopover.performClose(sender) 
    } else { 
     if let button = statusItem.button { 
      // set the button's highlighted property to true 
      dispatch_async(dispatch_get_main_queue(), { 
       button.highlighted = true 
      }) 

      appPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: NSRectEdge.MinY) 
     } 
    } 

Questo funziona, ma si potrebbe notare un po 'di sfarfallio a causa dello stato tasto venga modificata da ON a OFF e poi di nuovo su ON. L'OFF si verifica a causa della visualizzazione del popover. Quindi, per risolvere il problema, sposta la chiamata appPopover.showRelativeToRect() all'interno del blocco dispatch_async(), subito dopo aver impostato il pulsante evidenziato.

+0

Appare ancora lo sfarfallio. – njuri

4

Ecco un'altra opzione. Non impostare la proprietà action di . Invece aggiungere un monitor evento locale:

[NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDown | NSRightMouseDown) 
             handler:^NSEvent *(NSEvent *event) { 
              if (event.window == self.statusItem.button.window) { 
               [self itemClicked]; 
               return nil; 
              } 
              return event; 
             }]; 

Poi nel -itemClicked Evidenziare il pulsante con highlight: metodo:

- (void)itemClicked { 
    [self.statusItem.button highlight:YES]; 
    // Do other stuff 
} 

Per unhighlight basta chiamare il pulsante di highlight:NO in cui è necessario.

3

Risposta Swift 3 della risposta Manfred Urban's. Lavori su El Capitan.

extension NSStatusBarButton { 

    public override func mouseDown(_ event: NSEvent) { 

     if (event.modifierFlags.contains(NSControlKeyMask)) { 
      self.rightMouseDown(event) 
      return 
     } 

     self.highlight(true) 

     (self.target as? TrivialTargetClass)?.togglePopover() 
    } 
} 

Non dimenticare di impostare nuovamente i pulsanti evidenziare la proprietà su falso, se necessario.

+0

Funziona anche su Sierra. – rsfinn

-1

La soluzione di Anton è perfetta. Qui è in Swift 3:

NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { [weak self] event in 
    if event.window == self?.statusItem.button?.window { 
     // Your action: 
     self?.togglePopover(self?.statusItem.button) 
     return nil 
    } 

    return event 
} 

ho aggiunto un osservatore per NSApplicationWillResignActive per chiudere la popover e impostare il isHighlighted-false pulsante.

Problemi correlati