2009-07-29 8 views
7

Tengo un NSSegmentedControl en mi UI con 4 botones. El control está conectado a un método que va a llamar a diferentes métodos dependiendo de que se hace clic segmento:Mostrar el menú NSSegmentedControl cuando se hace clic en un segmento, a pesar de tener acción establecida

- (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 tiene tiene un menú que se le atribuye en el método awakeFromNib. Me gustaría que este menú se desplegara cuando el usuario hace clic en el segmento. En este punto, solo se soltará si el usuario hace clic en & se mantiene presionada en el menú. De mi investigación en línea, esto se debe a la acción conectada.

Actualmente estoy trabajando en ello usando algún código para obtener el punto de origen del control de segmento y apareciendo el menú contextual usando NSMenu popUpContextMenu:withEvent:forView pero esto es bastante hacktastic y se ve mal en comparación con el comportamiento estándar de tener el menú desplegable debajo de la celda de control segmentada.

¿Hay alguna manera de que pueda tener el menú desplegable como debería después de un solo clic en lugar de hacer el menú contextual de hacky?

+0

En 10.10.2/Xcode 6.3, el comportamiento estándar del menú es desplegable cuando el usuario hace clic en un segmento que no tiene ninguna acción asociada; y exigir que se presione y mantenga presionada cuando el segmento tiene una acción IBAction. Como su acción es 'mostrar menú', debería poder eliminarla. –

+0

¿Cómo adjuntas acciones a segmentos individuales? –

Respuesta

3

No estoy seguro de ninguna forma integrada de hacerlo (aunque realmente es un agujero evidente en la API NSSegmentedControl).

Mi recomendación es continuar haciendo lo que está haciendo apareciendo el menú contextual. Sin embargo, en lugar de usar el origen del control segmentado, puede colocarlo directamente bajo el segmento (como usted quiere) de la siguiente manera:

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

No es perfecto o ideal, pero hay que hacer el trabajo y dar la apariencia/comportamiento que esperan sus usuarios.

(como un aparte, NSSegmentedControl realmente necesita un método -rectForSegment:)

+1

Está de acuerdo en que es bastante cojo que no hay una forma incorporada de hacerlo. Lo archivé en Radar. Dupe away: http://openradar.appspot.com/radar?id=61419 –

2

widthForSegment: devuelve cero si el segmento de automóviles tamaños. Si no está preocupado por las API de indocumentados, hay una rectForSegment:

  • (NSRect) rectForSegment: (NSInteger) segmento en marco: Marco (NSRect);

Pero para responder a la pregunta original, una manera más fácil para obtener el menú para que aparezca inmediatamente es subclase NSSegmentedCell y devolver 0 para (de nuevo, no documentada)

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

Subclase NSSegmentedCell, reemplaza el método a continuación y reemplaza la clase de celda en IB. (No requiere API privadas).

- (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

Esto funciona muy bien. De lejos, la solución más limpia que he visto. ¡Gracias! – djeckhart

+2

Buena solución, de hecho. Una sugerencia menor: establezca la condición if en '[self menuForSegment: [self selectedSegment]]! = Nil'; de esa manera no tienes que establecer etiquetas. –

+1

Este sorta funciona muy bien. Si el segmento aún no está seleccionado, al hacer clic en él no se hace nada. Clics luego de seleccionar el segmento y luego producir el menú. No puedo ver cómo funciona esto para ustedes sin ajustar ese comportamiento. –

3

Esta es la versión Swift de la respuesta de J Hoover y la mod de Adam Treble. La anulación no fue tan intuitiva como pensé que sería, así que esto ayudará a alguien más.

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

Lo hice, pero por alguna razón nunca se llama al método 'get'. –

Cuestiones relacionadas