2011-12-09 9 views
8

Questa è la mia prima domanda qui, e cercherò di farlo il più chiaro possibile.NSTableView: come disegnare una separatori personalizzati prima e dopo una riga selezionata

voglio disegnare un gradiente personalizzato su una riga selezionata in un NSTableView in base alla vista, mentre l'aggiunta di un effetto a rilievo sottile. Per questo, ho bisogno di usare un colore più scuro per le linee della griglia che sono prima e dopo la riga selezionata (vedi here per un esempio). Ho annullato il metodo in NSTableRowView per disegnare la linea di separazione personalizzata per la riga selezionata (utilizzando il metodo isSelected come bandiera), ma non posso fare lo stesso per quello sopra/sotto (poiché disegno la linea in basso/superiore).

Ho provato diversi modi per dire alla riga più vicina che dovrebbe disegnare una linea di separazione più scura senza successo poiché la fase di visualizzazione non segue lo stesso ordine (l'ho verificata con NSlog nel drawSeparatorInRect:, e sembra che quando si scorre un po 'le modifiche di questo ordine). Quindi, a volte (principalmente dopo lo scorrimento) la riga non sa che dovrebbe usare un colore più scuro poiché si disegna prima di quella selezionata (penso che a questo punto, la riga selezionata non sia ancora consapevole che è selezionata, altrimenti io non capisco cosa sta succedendo).

Alcune delle cose che ho provato:

  1. Nel metodo della riga selezionata drawSeparatorInRect:, ho cercato di accedere alle viste fratelli ([superview subviews]) e forzare il precedente/successiva disegnare stessa nuovamente.
  2. Dalla sottoclasse NSTableView, modificare direttamente la riga più vicina quando la modifica selezionataIndexes cambia.
  3. Disegnare la linea esterna della riga selezionata dall'interno suo metodo drawSeparatorInRect: come mostra here.

noti che ho fatto avente: una fila vista chiede se è selezionata la precedente/successiva, un closestRowIsSelected bandiera o chiamando esternamente un metodo per "forza" il colore scuro.

Quello che ho ora è che la riga selezionata disegna entrambi i bordi superiore e inferiore, quindi uno di essi è posizionato insieme alla riga precedente/successiva ... È sottile ma è ancora lì.

Qualsiasi aiuto sarà ben accolto.

Grazie in anticipo.

! non ho postato alcun codice dal momento che il problema non è lì (solo chiamate [NSBezierPath fillRect:rect] con il colore rosso), credo ... quindi non ho nulla da mostrare.

risposta

12

Ho anche provato questo e ho notato che drawSeparatorInRect: può davvero disegnare la sua linea di separazione inferiore come la posizione della linea di separazione superiore (che è la stessa linea di separazione inferiore della riga precedente) è un pixel all'esterno (sopra) il clipRect della riga.

Tuttavia, ho ottenuto che funziona sottoclasse NSTableRowView ed avente drawSeparatorInRect: come segue:

- (void)drawSeparatorInRect:(NSRect)dirtyRect 
{ 
    // Define our drawing colors 
    NSColor *normalColor = [NSColor colorWithCalibratedWhite:0.76 alpha:1.0]; // Default separator color 
    NSColor *selectedTopColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the top separator line of selected row 
    NSColor *selectedBottomColor = [NSColor colorWithCalibratedWhite:0.60 alpha:1.0]; // Color of the bottom separator line of selected row 

    // Define coordinates of separator line 
    NSRect drawingRect = [self frame]; // Ignore dirtyRect 
    drawingRect.origin.y = drawingRect.size.height - 1.0; 
    drawingRect.size.height = 1.0; // Height of the separator line we're going to draw at the bottom of the row 

    // Get the table view and info on row index numbers 
    NSTableView *tableView = (NSTableView*)[self superview]; // The table view the row is part of 
    NSInteger selectedRowNumber = [tableView selectedRow]; 
    NSInteger ownRowNumber = [tableView rowForView:self]; 

    // Set the color of the separator line 
    [normalColor set]; // Default 
    if (([self isSelected]) && ((selectedRowNumber + 1) < [tableView numberOfRows])) [selectedBottomColor set]; // If the row is selected, use selectedBottomColor 
    if ((![self isSelected]) && (selectedRowNumber > 0) && (ownRowNumber == (selectedRowNumber-1))) [selectedTopColor set]; // If the row is followed by the selected row, draw its bottom separator line in selectedTopColor 

    // Draw separator line 
    NSRectFill (drawingRect); 

    // If the row is selected, tell the preceding row to redraw its bottom separator line (which is also the top line of the selected row) 
    if (([self isSelected]) && (selectedRowNumber > 0)) [tableView setNeedsDisplayInRect:[tableView rectOfRow:selectedRowNumber-1]]; 
} 

Questo metodo (solo) disegnare una propria linea di separazione inferiore.Se è la riga selezionata, disegna la linea non con il colore predefinito, ma evidenziata, quindi dirà anche alla riga precedente di ridisegnare la sua linea di separazione, vale a dire la stessa riga del separatore superiore della riga selezionata.

Per ottenere questo risultato, la riga sopra la riga selezionata deve ridisegnare la riga del separatore inferiore una volta spostata la selezione. Ho raggiunto questo avendo questo metodo nel delegato NSTableView:

// Tell the row above the row which is going to loose the selection to redraw its bottom separator line 
- (BOOL)selectionShouldChangeInTableView:(NSTableView *)aTableView 
{ 
    NSInteger selectedRowNumber = [aTableView selectedRow]; 
    if (selectedRowNumber > 0) { 
    [aTableView setNeedsDisplayInRect:[aTableView rectOfRow:selectedRowNumber-1]]; 
    } 
    return YES; 
} 

Questo metodo delegato indica la riga sopra la riga selezionata di ridisegnare la sua linea di separazione. Si chiama immediatamente prima che la selezione cambi.

+0

In realtà la documentazione di Apple risulta essere corretta: il bevaviour predefinito di NSTableRowView consiste nel disegnare la linea di separazione nella parte inferiore della riga, non nella parte superiore. Ho modificato l'esempio di codice sopra di conseguenza. – Tim

+0

Grazie mille, fa sicuramente quello che stavo cercando di fare. Tuttavia, ogni volta che seleziono una riga o scorro la vista tabella, la riga da precedente a selezionata si ridisegna più volte, producendo un testo ultra-grassetto e altri effetti strani. Ho dimenticato qualcosa? –

+0

Ho funzionato perfettamente con il mio vecchio codice. Tuttavia, ho spostato la parte di codice che forza la visualizzazione della cella precedente a disegnarsi, situata alla fine del metodo 'drawSeparatorInRect:', a un metodo delegato che mi dà la nuova riga selezionata (ho usato 'tableView: shouldSelectRow:') . Ancora una volta, grazie per il vostro aiuto. –

Problemi correlati