2009-07-29 4 views
7

Ho un NSSegmentedControl sulla mia interfaccia utente con 4 pulsanti. Il controllo è collegato ad un metodo che chiamare metodi differenti a seconda del segmento viene cliccato:Mostra menu NSSegmentedControl quando il segmento ha fatto clic, nonostante abbia impostato l'azione

- (IBAction)performActionFromClick:(id)sender { 
    NSInteger selectedSegment = [sender selectedSegment]; 
    NSInteger clickedSegmentTag = [[sender cell] tagForSegment:selectedSegment]; 

    switch (clickedSegmentTag) { 
      case 0: [self showNewEventWindow:nil]; break; 
      case 1: [self showNewTaskWindow:nil]; break; 
      case 2: [self toggleTaskSplitView:nil]; break; 
      case 3: [self showGearMenu]; break; 
    } 
} 

Segmento 4 ha ha un menu collegato ad esso nel metodo awakeFromNib. Mi piacerebbe che questo menu scendesse quando l'utente fa clic sul segmento. A questo punto, scenderà solo se l'utente fa clic su & sul menu. Dalla mia ricerca online questo è dovuto all'azione connessa.

Attualmente sto lavorando attorno ad esso usando del codice per ottenere il punto di origine del controllo del segmento e facendo apparire il menu di contesto usando NSMenu popUpContextMenu:withEvent:forView ma questo è piuttosto hacktastic e sembra male rispetto al comportamento standard di avere il menu scendi sotto la cella di controllo segmentata.

C'è un modo per fare in modo che il menu si abbassi come dovrebbe dopo un singolo clic piuttosto che fare la cosa del menu contestuale hacky?

+0

In 10.10.2/Xcode 6.3 il comportamento standard per il menu è di cadere verso il basso quando l'utente seleziona un segmento che ha alcuna azione attaccato; e richiedere il click-and-hold quando il segmento ha un IBAction. Poiché la tua azione è "mostra menu" dovresti essere in grado di rimuoverla. –

+0

Come si collegano le azioni ai singoli segmenti? –

risposta

3

Non sono sicuro di alcun modo incorporato per farlo (sebbene sia davvero un buco nell'API NSSegmentedControl).

La mia raccomandazione è di continuare a fare quello che stai facendo spuntando il menu di scelta rapida. Tuttavia, invece di utilizzare l'origine del controllo segmentato, si potrebbe posizionarlo direttamente sotto il segmento (come si vuole), effettuando le seguenti operazioni:

NSPoint menuOrigin = [segmentedControl frame].origin; 
menuOrigin.x = NSMaxX([segmentedControl frame]) - [segmentedControl widthForSegment:4]; 
// Use menuOrigin where you _were_ just using [segmentedControl frame].origin 

Non è perfetto o ideale, ma dovrebbe ottenere il lavoro fatto e dare l'aspetto/comportamento che gli utenti si aspettano.

(Per inciso, NSSegmentedControl davvero ha bisogno di un metodo di -rectForSegment:)

+1

Concordato che è piuttosto zoppo non esiste un modo integrato per farlo. L'ho registrato su Radar. Dupe via: http://openradar.appspot.com/radar?id=61419 –

2

widthForSegment: restituisce zero se il segmento auto-formati. Se non siete preoccupati per le API non documentate, v'è un rectForSegment:

  • (NSRect) rectForSegment: (NSInteger) segmento inFrame: (NSRect) telaio;

Ma per rispondere alla domanda iniziale, un modo più semplice per ottenere il menu a pop-up subito è quello di creare una sottoclasse NSSegmentedCell e restituire 0 per (di nuovo, non documentato)

  • (doppia) _menuDelayTimeForSegment: (NSInteger)segmento;
14

Sottoclasse NSSegmentedCell, metodo di override di seguito e sostituzione della classe di cella in IB. (Non richiede API private).

- (SEL)action 
{ 
    //this allows connected menu to popup instantly (because no action is returned for menu button) 
    if ([self tagForSegment:[self selectedSegment]]==0) { 
     return nil; 
    } else { 
     return [super action]; 
    } 
} 
+1

Funziona alla grande. Di gran lunga la soluzione più pulita che ho visto. Grazie! – djeckhart

+2

Bella soluzione, davvero. Un piccolo suggerimento: imposta la condizione if a '[self menuForSegment: [self selectedSegment]]! = Nil'; in questo modo non devi impostare i tag. –

+1

Questo tipo funziona alla grande. Se il segmento non è già selezionato, facendo clic su di esso non fa nulla. I clic dopo che il segmento è stato selezionato producono il menu. Non riesco a vedere come funzioni per voi ragazzi senza adeguare questo comportamento. –

3

Questa è la versione Swift della risposta di J Hoover e la mod di Adam Treble. L'override non era così intuitivo come pensavo, quindi speriamo che possa aiutare qualcun altro.

override var action : Selector { 
     get { 
      if self.menuForSegment(self.selectedSegment) != nil { 
       return nil 
      } 
      return super.action 
     } 
     set { 
      super.action = newValue 
     } 
    } 
+0

Ho fatto questo, ma per qualche motivo il metodo 'get' non viene mai chiamato. –