30

Tengo un NSCollectionView que funciona con una excepción menor, pero crítica. Obtener y resaltar el elemento seleccionado dentro de la colección.Resaltado de selección en NSCollectionView

He tenido todo esto funcionando antes de Snow Leopard, pero parece que algo ha cambiado y no puedo ubicarlo, así que tomé mi NSCollectionView de vuelta a una prueba básica y seguí la documentación de Apple para la creación de un NSCollectionView aquí:

http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/CollectionViews/Introduction/Introduction.html

ver la colección funciona bien siguiendo la guía de inicio rápido. Sin embargo, esta guía no analiza la selección que no sea "There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

Usando esto como un ejemplo fui a la siguiente etapa de unir el controlador de matrices a la NSCollectionView con la clave de controlador selectionIndexes, pensando que esto obligaría a cualquier selección hago entre el NSCollectionView y el controlador de matriz y por lo tanto disparando una Notificación KVO. También configuré el NSCollectionView para que se pueda seleccionar en IB.

Parece que no hay un delegado de selección para NSCollectionView y, a diferencia de la mayoría de las vistas de la interfaz de usuario de Cocoa, parece que no hay ningún resaltado seleccionado por defecto.

Así que mi problema realmente se reduce a un problema relacionado, pero hay dos preguntas distintas.

  1. ¿Cómo puedo capturar una selección de un artículo?
  2. ¿Cómo se muestra el resaltado de un elemento?

NSCollectionView 's guías de programación parecen ser pocos y distantes entre sí y la mayoría de las búsquedas a través de Google aparecerá para levantar implementaciones Leopard pre-nieve, o utilizar la vista en un archivo separado XI ter.

Para este último (archivo XIB separado para la vista), no veo por qué esto debería ser un requisito previo de lo contrario habría sospechado que Apple no habría incluido la vista en el mismo paquete que la vista de colección ít.

Sé que esto va a ser un problema de "no puedo ver la madera por los árboles", así que estoy preparado para el "¡do!" momento.

Como siempre, cualquier y toda ayuda fue muy apreciada.

Actualización 1

bien, así que pensé encontrar el artículo (s) seleccionado, pero todavía tienen que calcular el resaltado.Para los interesados ​​en averiguar los elementos seleccionados (si se asume que está siguiendo la guía de Apple):

En el controlador (en mi caso de prueba de la aplicación Delegado) he añadido lo siguiente:

En awakeFromNib

[personArrayController addObserver:self 
     forKeyPath:@"selectionIndexes" 
     options:NSKeyValueObservingOptionNew 
     context:nil]; 

Nuevo método

-(void)observeValueForKeyPath:(NSString *)keyPath 
        ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    if([keyPath isEqualTo:@"selectionIndexes"]) 
    { 
     if([[personArrayController selectedObjects] count] > 0) 
     { 
      if ([[personArrayController selectedObjects] count] == 1) 
      { 
       personModel * pm = (PersonModel *) 
         [[personArrayController selectedObjects] objectAtIndex:0]; 
       NSLog(@"Only 1 selected: %@", [pm name]); 
      } 
      else 
      { 
       // More than one selected - iterate if need be 
      } 
     } 
    } 

No se olvide de dealloc para los no-GC

-(void)dealloc 
{ 
    [personArrayController removeObserver:self 
           forKeyPath:@"selectionIndexes"]; 
    [super dealloc]; 
} 

Sigue búsqueda de la solución más destacado ...

Actualización 2

siguió el consejo de Macatomy pero todavía tenía un problema. Publicando los métodos de clase relevantes para ver dónde me he equivocado.

MyView.h

#import <Cocoa/Cocoa.h> 

@interface MyView : NSView { 
    BOOL selected; 
} 

@property (readwrite) BOOL selected; 

@end 

MyView.m

#import "MyView.h" 

@implementation MyView 

@synthesize selected; 

-(id)initWithFrame:(NSRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code here. 
    } 
    return self; 
} 

-(void)drawRect:(NSRect)dirtyRect 
{ 
    NSRect outerFrame = NSMakeRect(0, 0, 143, 104); 
    NSRect selectedFrame = NSInsetRect(outerFrame, 2, 2); 

    if (selected) 
     [[NSColor yellowColor] set]; 
    else 
     [[NSColor redColor] set]; 

    [NSBezierPath strokeRect:selectedFrame]; 
} 

@end 

MyCollectionViewItem.h

#import <Cocoa/Cocoa.h> 
@class MyView; 

@interface MyCollectionViewItem : NSCollectionViewItem { 

} 

@end 

"MyCollection ViewItem.m *

#import "MyCollectionViewItem.h" 
#import "MyView.h" 

@implementation MyCollectionViewItem 

-(void)setSelected:(BOOL)flag 
{ 

    [(MyView *)[self view] setSelected:flag]; 
    [(MyView *)[self view] setNeedsDisplay:YES]; 
} 

@end 

Respuesta

25

No es demasiado difícil de hacer. Asegúrese de que "Selección" esté habilitado para NSCollectionView en Interface Builder. Luego, en la subclase NSView que está utilizando para la vista prototipo, declarar una propiedad llamada "seleccionado":

@property (readwrite) BOOL selected; 

código actualizado AQUÍ: (añadido llamada súper)

Subclase NSCollectionViewItem y anular -setSelected :

- (void)setSelected:(BOOL)flag 
{ 
    [super setSelected:flag]; 
    [(PrototypeView*)[self view] setSelected:flag]; 
    [(PrototypeView*)[self view] setNeedsDisplay:YES]; 
} 

Luego hay que añadir código en drawRect de su vista prototipo: método para dibujar el punto culminante:

- (void)drawRect:(NSRect)dirtyRect 
{ 
    if (selected) { 
     [[NSColor blueColor] set]; 
     NSRectFill([self bounds]); 
    } 
} 

Eso simplemente llena la vista en azul cuando está seleccionada, pero puede personalizarse para dibujar el resaltado de la forma que desee. Lo he usado en mis propias aplicaciones y funciona muy bien.

+0

Macatomy, definitivamente un "Doh!" momento de leer su solución, pero después de intentar su sugerencia no tuvo suerte, lo que sugiere que tal vez tenga un problema con mi PrototypeView. Puedo capturar el evento de selección con el KVO, así que sé que collectionView (y, posteriormente, el controlador de array) está seleccionando la selección, y puedo consultar el objeto del modelo seleccionado, pero no estoy llamando a 'setSelected'. 'selected' devuelve false cada vez. ¿Alguna idea? Publicaré las clases si eso ayuda. – Hooligancat

+0

Asegúrese de que en Interface Builder su elemento de vista de colección y la vista de prototipo tengan su identidad de clase establecida en la subclase adecuada en lugar de solo el NSCollectionViewItem y NSView predeterminados. Si has hecho esto, entonces sí, publicar las clases sería útil :) – indragie

+0

Soy un idiota. Olvidé establecer la clase identificada para CollectionViewItem en IB ... – Hooligancat

33

Si un color de fondo diferente será suficiente como resaltado, simplemente podría usar un NSBox como elemento raíz para su vista de elemento de colección. Llena el NSBox con el color de resalte que elijas. Establezca NSBox en Personalizado para que el relleno funcione. Establezca NSBox en transparente.

Enlace el atributo de transparencia de NSBox con el atributo seleccionado de Propietario de archivo (Elemento de recopilación) Establezca el transformador de valor para el enlace transparente a NSNegateBoolean.

Me trataron de unir las capturas Interface Builder pero fue rechazado bcos Soy un novato :-(

+0

¡Votado para esto, toma exactamente 30 segundos para implementar y es suficiente para casi todos los escenarios que tengo! – tempy

+0

Gran respuesta, y como nota si desea un "estilo" diferente para el fondo de selección simplemente use su propia (o una opción deseable) alternativa para NSBox, las mismas fijaciones funcionarán. – rougeExciter

+0

Cuando dice "simplemente use un NSBox como el elemento raíz para su vista de elemento de colección", creo que quiere decir poner un NSBox en el NSView. Si intentas cambiar el NSView en un NSBox, Interface Builder no te deja configurar sus parámetros y probablemente sea solo un triste reflejo de mi comprensión del Cocoa que incluso intenté. – bitmusher

0

Esto fue impresionante, gracias mucho! He tenido problemas con esto!

para aclarar a los demás :

[(PrototypeView*)[self view] setSelected:flag]; 
[(PrototypeView*)[self view] setNeedsDisplay:YES]; 

Reemplazar PrototypeView * con el nombre de su nombre de la clase prototipo

+1

Hola Rasmus, me alegro de que funcionó para ti. He descubierto que Stack Overflow es increíblemente útil, especialmente cuando alguien más se ha encontrado con un problema similar y la comunidad se ha reunido para ayudar a encontrar una respuesta. – Hooligancat

1

también puede ir de otra manera, si no estás de subclases NSView. para su vista de prototipo

En su anulación subclase NSCollectionViewItem setSelected:

- (void)setSelected:(BOOL)selected 
{ 
    [super setSelected:selected]; 
    if (selected) 
     self.view.layer.backgroundColor = [NSColor redColor].CGColor; 
    else 
     self.view.layer.backgroundColor = [NSColor clearColor].CGColor; 
} 

Y, por supuesto, como se dice por todos los sabios antes que yo, asegúrese de "Selección" está habilitado para el NSCollectionView en Interface Builder.

+0

Mi '- (void) setSelected: (BOOL) selected' no se activa. ¿Cuál podría ser el problema? – Jamil

1

En mi caso, quería una imagen (marca de verificación) para indicar la selección del objeto. Arrastre un ImageWell a la punta del elemento de colección. Establezca la imagen deseada y márquela como oculta. Vaya al inspector de enlaces y enlace el atributo oculto al elemento de vista de colección.

enter image description here

(En mi caso yo había creado una punta separada para CollectionViewItem, por lo que su Binded propietario del archivo. Si este no es el caso y la vista del artículo está en la misma punta como el CollectionView continuación, se unen a Colección Ver artículo)

Establezca la ruta de la clave del modelo como selected y Transformador de valor en NSNegateBoolean. Eso es ahora, cada vez que se seleccionan las celdas/elementos individuales, la imagen será visible, lo que indica la selección.

Agregando a la respuesta de Alter.

Para establecer NSBox como elemento raíz. Simplemente cree un nuevo documento IB (digamos CollectionItem) y arrastre un NSBox al área vacía. Ahora agregue todos los elementos según sea necesario dentro del cuadro. Ahora haga clic en Propietario de archivo y configure Clase personalizada como NSCollectionViewItem.

enter image description here

Y en la punta donde se añade NSCollectionView cambiar el nombre de la semilla CollectionViewItem

enter image description here

En el NSBox, se unen los elementos restantes para Files Owner.Para una etiqueta que sería similar a:

enter image description here

Ahora para obtener el color de resaltado como Alter menciona en su respuesta, la combinación determinada del color deseado en la opción Color de relleno, ajuste el NSBox a transparente y se unen la transparencia de atributos de la siguiente manera:

enter image description here

Ahora, cuando se seleccionan Colección Artículos de la visión que debería ser capaz de ver el color de relleno de la caja.

2

Dado que ninguna de las respuestas existentes funcionó muy bien para mí, esta es mi opinión. Cambie la subclase del elemento CollectionView a SelectableCollectionViewItem. Aquí está su código. Viene con una propiedad enlatable textColor para enganchar su etiqueta de texto textColor binding a.

@implementation SelectableCollectionViewItem 

+ (NSSet *)keyPathsForValuesAffectingTextColor 
{ 
    return [NSSet setWithObjects:@"selected", nil]; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.view.wantsLayer = YES; 
} 

- (void) viewDidAppear 
{ 
    // seems the inital selection state is not done by Apple in a KVO compliant manner, update background color manually 
    [self updateBackgroundColorForSelectionState:self.isSelected]; 
} 

- (void)updateBackgroundColorForSelectionState:(BOOL)flag 
{ 
    if (flag) 
    { 
     self.view.layer.backgroundColor = [[NSColor alternateSelectedControlColor] CGColor]; 
    } 
    else 
    { 
     self.view.layer.backgroundColor = [[NSColor clearColor] CGColor]; 
    } 
} 

- (void)setSelected:(BOOL)flag 
{ 
    [super setSelected:flag]; 
    [self updateBackgroundColorForSelectionState:flag]; 
} 

- (NSColor*) textColor 
{ 
    return self.selected ? [NSColor whiteColor] : [NSColor textColor]; 
} 
Cuestiones relacionadas