2009-09-30 5 views
5

Il mini-player di iTunes (per fare solo un esempio) supporta il click-through in cui l'applicazione non viene portata in primo piano quando vengono utilizzati i controlli riproduzione/pausa e volume.Pulsanti click-through e non sollevamento della finestra

Come è fatto?

ho cercato attraverso la documentazione di Apple e ho un po 'di andare avanti, in Cocoa Event-Handling Guide, Event Dispatch afferma:

Alcuni eventi, molti dei quali sono definiti dal Kit applicazione (tipo NSAppKitDefined), devono fare con le azioni controllate da una finestra o dall'oggetto dell'applicazione stesso. Esempi di questi eventi sono quelli relativi all'attivazione, disattivazione, occultamento e visualizzazione dell'applicazione. NSApp filtra questi eventi all'inizio della sua routine di invio e li gestisce autonomamente.

Così, dalla mia comprensione limitata (How an Event Enters a Cocoa, Application) sottoclassi NSApplication e prioritario - (void)sendEvent:(NSEvent *)theEvent dovrebbe trappola ogni mouse e tastiera evento, ma ancora, la finestra è sollevata al clic. Quindi la finestra viene sollevata prima che l'evento venga visto da NSApplication o mi manca qualcos'altro.

Ho guardato di Matt Gallagher Demystifying NSApplication by recreating it, purtroppo Matt non ha coperto la coda di eventi, in modo diverso da quello, io sono perplesso.

Qualsiasi aiuto sarebbe apprezzato, grazie.

A cura di aggiungere: trovato un post a Lloyd's Lounge in cui parla lo stesso problema e link ad un post a CocoaBuilder, capture first right mouse down. Al momento sto provando il codice fornito lì, dopo un po 'di giocherellando e riattivando NSLog per [il tipoEvent], l'attività del tasto sinistro del mouse viene catturata.

Ora, facendo clic con il tasto sinistro sulla finestra per portarla in avanti, viene generata una sequenza di tipi di eventi, 13, 1, 13, questi sono nuovamente NSAppKitDefined, NSLeftMouseDown e NSAppKitDefined. Posso filtrarli o trovare dove stanno andando?

risposta

2

Questa non è esattamente la risposta che stavo cercando, ma per ora funziona sufficientemente bene. Sottoclasse NSView e l'implementazione dei seguenti metodi, tale visualizzazione può quindi fungere da pulsante.

- (void)mouseDown:(NSEvent *)theEvent { 
    [NSApp preventWindowOrdering]; 
// [self setNeedsDisplay:YES]; 
} 

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { 
    return YES; 
} 

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent { 
    return YES; 
} 

Nient'altro è richiesto, è tutto. Ovviamente questo scavalca tutta la bontà di NSButton che volevo mantenere, devo progettare e quindi occuparmi di disegnare e aggiornare gli stati dei pulsanti, ma sono contento di avere una risposta.

1

Avete controllato acceptsFirstMouse:? Qualsiasipuò restituire YES a questo evento per dire che la vista dovrebbe gestire l'evento piuttosto che portare la finestra in primo piano. Presumibilmente, intercettando l'evento, non sarà usato per portare la finestra in primo piano, ma non posso garantire per quello.

Ovviamente è necessario sottoclasse qualsiasi controllo per il quale si desidera che questo comportamento venga sostituito da acceptsFirstMouse:.

+0

accettaFirstMouse: e accettaPrimoResponder: non ha alcun effetto, è stato (e avrei dovuto notare) il mio primo tentativo a questo problema. Grazie comunque. –

3

Questo può essere eseguito con un NSPanel che è stato impostato per non nascondere su disattivato e per diventare chiave solo se necessario. Ciò presuppone anche che i controlli che utilizzerai restituiscano YES a -acceptsFirstMouse:; NSButton lo fanno di default.

È possibile disattivare il contrassegno di disattivazione della disattivazione tramite IB per il pannello, ma è necessario inviare il messaggio -setBecomesKeyOnlyIfNeeded:YES al pannello per mantenerlo e l'app non si presenta in avanti sui clic del pulsante.

+0

Voglio credere che questa sia la risposta, ma leggendo il riferimento alla classe NSView (dove è definito il metodo 'acceptFirstMouse:') si dice che è impostato su 'NO'. E infine la sottoclasse di 'NSView' non fa differenza in ogni caso. –

+0

Ho appena trovato una breve discussione su CocoaDev, http://www.cocoadev.com/index.pl?PreventWindowOrdering, questo fa quello che voglio, sembra comunque un brutto modo di farlo. –

+0

I documenti per 'acceptFirstMouse:' specificano 'NSButton' come restituito' YES': "Molti oggetti di controllo, tuttavia, come le istanze di' NSButton' e 'NSSlider', li accettano, quindi l'utente può immediatamente manipola il controllo senza dover rilasciare il pulsante del mouse. " –

2

E 'possibile fare un NSButton risponde ai click-through di eventi senza cambiare il suo comportamento quando l'applicazione è attiva:

Interface (ClickThroughButton.h):

#import <AppKit/AppKit.h> 

@interface ClickThroughButton : NSButton 

@end 

attuazione (ClickThroughButton.m) :

#import "ClickThroughButton.h" 

@implementation ClickThroughButton 

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent { 
    return ![NSApp isActive];  
} 

- (void)mouseDown:(NSEvent *)theEvent {  
    if (![NSApp isActive]) { 
     [NSApp preventWindowOrdering];   

     [self highlight:YES]; 

     NSEvent *mouseUpEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask 
                untilDate:[NSDate distantFuture] 
                inMode:NSEventTrackingRunLoopMode 
                dequeue:YES]; 
     NSPoint mouseLocation = [self convertPoint:[mouseUpEvent locationInWindow] fromView:nil]; 
     BOOL mouseUpInside = [self mouse:mouseLocation inRect:[self bounds]]; 

     if (mouseUpInside) { 
      if ([self target]) 
       [[self target] performSelector:[self action] withObject:self]; 
     } 

     [self highlight:NO];    

    } else { 
     [super mouseDown:theEvent];   
    } 
} 

@end 
+0

Funziona, ma come mantenere il dialogo in primo piano? Sto sviluppando un'applicazione come Keyboard Viewer. –

Problemi correlati