2012-01-29 1 views
17

Je fais une application qui vit dans la barre d'état. Lorsque l'élément d'état est cliqué, NSPopover apparaît.Transcision de NSPopover quand popover est dans la barre d'état

Il ressemble à ceci:

enter image description here

Voici le problème: je veux que ce soit « transitoire », qui est si je clique partout en dehors de la popover, il fermera. Et tandis que NSPopoverBehaviorTransient fonctionne correctement lorsque Popover est dans une fenêtre, cela ne fonctionne pas quand il est dans la barre d'état.

Comment puis-je implémenter un tel comportement moi-même?

Répondre

28

Il est avéré être facile:

- (IBAction)openPopover:(id)sender 
{ 
    // (open popover) 

    if(popoverTransiencyMonitor == nil) 
    { 
     popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask handler:^(NSEvent* event) 
            { 
             [self closePopover:sender]; 
            }]; 
    } 
} 

- (IBAction)closePopover:(id)sender 
{ 
    if(popoverTransiencyMonitor) 
    { 
     [NSEvent removeMonitor:popoverTransiencyMonitor]; 

     popoverTransiencyMonitor = nil; 
    } 

    // (close popover) 
} 

Ce qui n'a pas été facile, cependant, est qu'il ya des problèmes désagréables d'avoir un pop popover sur NSStatusItem (il ne se comportait pas comme désiré lorsque la mission Le contrôle a été invoqué ou l'espace a été remplacé par une fenêtre en plein écran). J'ai dû implémenter une fenêtre personnalisée qui flotte toujours au-dessus de NSStatusItem et traite du passage à une fenêtre en plein écran, etc. Cela semblait facile, mais clairement les éléments d'état n'étaient pas conçus pour ça;)

+5

Pour un comportement cohérent avec celui des éléments d'état du système: 'addGlobalMonitorForEventsMatchingMask: NSLeftMouseDownMask | NSRightMouseDownMask' - de sorte que les clics droits ferment également le popover. – inket

7

J'utilise est similaire à la réponse ci-dessus, sauf que j'ai tout combiné en une seule méthode au lieu d'utiliser deux IBActions distinctes.

D'abord, je déclare les propriétés suivantes

@property (strong, nonatomic) NSStatusItem *statusItem; 
@property (strong, nonatomic) NSEvent *popoverTransiencyMonitor; 
@property (weak, nonatomic) IBOutlet NSPopover *popover; 
@property (weak, nonatomic) IBOutlet NSView *popoverView; 

puis dans awakeFromNib Je mis en place l'élément de barre d'état

- (void)awakeFromNib { 

    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; 

    self.statusItem.title = @"Title"; 
    self.statusItem.highlightMode = YES; 
    self.statusItem.action = @selector(itemClicked:); 
} 

suivi de la méthode qui est appelée lorsque l'élément de la barre d'état est cliqué

- (void)itemClicked:(id)sender { 

    [[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; 

    if (self.popoverTransiencyMonitor == nil) { 
     self.popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyUpMask) handler:^(NSEvent* event) { 
      [NSEvent removeMonitor:self.popoverTransiencyMonitor]; 
      self.popoverTransiencyMonitor = nil; 
      [self.popover close]; 
     }]; 
    } 
} 

qui fait apparaître le popover et se ferme également lorsque l'utilisateur clique en dehors de la vue.

Notez que dans Interface Builder, vous devez définir le comportement du popover sur Transient pour que le popover se ferme lorsque l'utilisateur clique sur l'élément d'état.

Questions connexes