30

Ho un funzionamento NSCollectionView con un'eccezione minore, ma critica. Ottenere ed evidenziare l'oggetto selezionato all'interno della raccolta.Evidenziazione selezione in NSCollectionView

Ho avuto tutto questo lavoro prima di Snow Leopard, ma qualcosa sembra essere cambiato e non riesco a mettere il dito su di esso, così ho preso il mio NSCollectionView di nuovo ad un test di base e ho seguito la documentazione di Apple per la creazione di un NSCollectionView qui:

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

vista la collezione funziona bene seguendo la guida di avvio rapido. Tuttavia, questa guida non discute la selezione diversa da "There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

Usando questo come esempio sono andato alla fase successiva di legare il controller di array al NSCollectionView con il tasto di controllo selectionIndexes, pensando che questo avrebbe associare qualsiasi scelta che faccio tra il NSCollectionView e il controller di array e quindi sparando un Notifica KVO. Ho anche impostato il NSCollectionView per essere selezionabile in IB.

Sembra che non ci sia delegato di selezione per NSCollectionView e, a differenza della maggior parte delle visualizzazioni di Cocoa UI, non sembra esserci un'evidenziazione selezionata di default.

Quindi il mio problema si riduce a un problema correlato, ma due domande distinte.

  1. Come posso acquisire una selezione di un articolo?
  2. Come visualizzare un evidenziamento di un articolo?

NSCollectionView 's guide di programmazione sembrano essere pochi e rari e la maggior parte le ricerche tramite Google sembrano tirare su pre-neve implementazioni Leopard, oppure utilizzare la visualizzazione in un file XIB separato.

Per quest'ultimo (file XIB separato per la vista), non vedo perché questo dovrebbe essere un prerequisito altrimenti avrei sospettato che Apple non avrebbe incluso la vista nello stesso pacchetto della vista di raccolta articolo.

So che questo sarà un problema "non vedo il bosco per gli alberi" - quindi sono preparato per il "doh!" momento.

Come al solito, tutti e tutti gli aiuti molto apprezzati.

Update 1

OK, così ho pensato di trovare l'elemento selezionato (s), ma non hanno ancora capire l'evidenziazione.Per gli interessati sul calcolare gli elementi selezionati (supponendo che si sta seguendo la guida di Apple):

Nel controllore (nel mio caso di test App Delegato) ho aggiunto il seguente:

In awakeFromNib

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

Nuovo metodo

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

Non dimenticare di dealloc per i non-GC

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

Ancora alla ricerca per la risoluzione clou ...

Update 2

accolse il consiglio di Macatomy ma aveva ancora un problema. Pubblicare i metodi di classe pertinenti per vedere dove ho sbagliato.

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 

risposta

25

Non è troppo difficile da fare. Assicurarsi che "Selezione" sia abilitato per NSCollectionView in Interface Builder. Poi nella sottoclasse NSView che si sta utilizzando per la visualizzazione del prototipo, dichiarare una proprietà chiamata "selezionato":

@property (readwrite) BOOL selected; 

codice aggiornato QUI: (aggiunto Super chiamata)

sottoclasse NSCollectionViewItem e sovrascrivere -setSelected :

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

allora avete bisogno di aggiungere il codice in drawRect del vostro vista prototipo: il metodo per disegnare il momento clou:

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

Questo semplicemente riempie la vista in blu quando è selezionata, ma che può essere personalizzata per disegnare l'evidenziazione nel modo desiderato. L'ho usato nelle mie app e funziona benissimo.

+0

Macatomy, decisamente un "Doh!" momento di leggere la tua soluzione, ma dopo aver provato il tuo suggerimento non ha avuto fortuna - il che suggerisce che forse ho un problema con il mio PrototypeView. Posso catturare l'evento di selezione con il KVO, quindi so che collectionView (e successivamente il controller di array) sta selezionando la selezione - e posso interrogare l'oggetto del modello selezionato, ma non ottengo il richiamo di 'setSelected'. 'selected' restituisce false ogni volta. Qualche idea? Pubblicherò le lezioni se ciò sarebbe di aiuto. – Hooligancat

+0

Assicurarsi che in Interface Builder l'elemento della vista raccolta e la vista prototipo abbiano l'identità della classe impostata sulla sottoclasse corretta anziché solo su NSCollectionViewItem e NSView predefiniti. Se hai fatto questo, allora sì, pubblicare le lezioni sarebbe utile :) – indragie

+0

Sono un idiota. Ho dimenticato di impostare la classe identificata per CollectionViewItem in IB ... – Hooligancat

33

Se un colore di sfondo diverso è sufficiente come evidenziazione, è sufficiente utilizzare un NSBox come elemento radice per la vista della voce della raccolta. Riempi l'NSBox con il colore di evidenziazione di tua scelta. Imposta l'NSBox su Personalizzato in modo che il riempimento funzioni. Imposta l'NSBox su trasparente.

Associare l'attributo di trasparenza dell'NSBox all'attributo selezionato di Proprietario file (Elemento raccolta) Impostare il trasformatore di valori per il collegamento trasparente su NSNegateBoolean.

ho cercato di collegare l'interfaccia screenshot builder ma mi è stata respinta bcos Sono un principiante :-(

+0

Votato per questo richiede esattamente 30 secondi per implementare ed essere sufficiente per quasi tutti gli scenari che ho! – tempy

+0

Ottima risposta e, come nota, se si desidera uno "stile" diverso per lo sfondo di selezione, è sufficiente utilizzare la propria alternativa (o auspicabile) per NSBox, gli stessi collegamenti funzioneranno. – rougeExciter

+0

Quando dice "usa semplicemente un NSBox come elemento radice per la vista della tua collezione", penso che significhi inserire un NSBox nella NSView. Se provi a cambiare NSView in un NSBox, Interface Builder non ti permette di impostare i suoi parametri ed è probabilmente solo un triste riflesso della mia comprensione del Cocoa che ho persino provato. – bitmusher

0

Questo è stato fantastico, grazie molto! Stavo lottando con questo!

Per chiarire per gli altri :

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

Sostituire PrototypeView * con il nome del prototipo nome della classe

+1

Hey Rasmus, felice che abbia funzionato per te. Ho trovato che Stack Overflow è incredibilmente utile, specialmente quando qualcun altro si è imbattuto in un problema simile e la comunità si è raccolta per trovare una risposta. – Hooligancat

1

si può anche andare in un altro modo, se non sei sottoclassi NSView. per la tua vista prototipo.

Nella vostra sottoclasse NSCollectionViewItem sostituzione 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; 
} 

E naturalmente, come detto da tutte le persone sagge prima di me, assicurarsi che "Selection" è abilitato per la NSCollectionView in Interface Builder.

+0

My '- (void) setSelected: (BOOL) selected' non sta sparando. Quale potrebbe essere il problema? – Jamil

1

Nel mio caso volevo un'immagine (segno di spunta) per indicare la selezione dell'oggetto. Trascina un ImageWell sul pennino dell'oggetto Collection. Imposta l'immagine desiderata e contrassegnala come nascosta. Vai a inspector binding e associa l'attributo hidden a Collection View Item.

enter image description here

(Nel mio caso avevo creato un pennino separato per CollectionViewItem, per cui il suo binded proprietario del file. Se questo non è il caso e la vista: L'articolo è nella stessa pennino come il CollectionView quindi associare a Collection View Item)

Impostare il percorso della chiave del modello come selected e Trasformare valore su NSNegateBoolean. Ecco ora ogni volta che le singole celle/elementi sono selezionati l'immagine sarà visibile, quindi indicando la selezione.

In aggiunta alla risposta di Alter.

Per impostare NSBox come elemento principale. Basta creare un nuovo documento IB (ad esempio CollectionItem) e trascinare un NSBox nell'area vuota. Ora aggiungi tutti gli elementi necessari all'interno della scatola. Ora fai clic su File's Owner e imposta Custom Class come NSCollectionViewItem.

enter image description here

E nel pennino in cui viene aggiunto NSCollectionView cambiare il nome pennino per CollectionViewItem

enter image description here

Nel NSBox, legare gli elementi rimanenti per Files Owner.Per un'etichetta che sarebbe simile a:

enter image description here

Ora per ottenere il colore di evidenziazione come Alter menzionato nella sua risposta, impostare la combinazione di colore desiderata nell'opzione Colore di riempimento, impostare il NSBox a trasparente e legano la trasparenza attributo come di seguito:

enter image description here

Ora, quando si selezionano Collection visualizzare gli articoli si dovrebbe essere in grado di vedere il colore di riempimento della casella.

2

Poiché nessuna delle risposte esistenti ha funzionato molto bene per me, ecco la mia opinione. Cambia la sottoclasse dell'oggetto CollectionView in SelectableCollectionViewItem. Ecco il codice. Viene fornito con una proprietà textCind bindable per l'aggancio del testo dell'etichetta 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]; 
}