2011-12-09 16 views
8

Esta es mi primera pregunta aquí, y trataré de hacerlo lo más claro posible.NSTableView: Cómo dibujar un separador personalizado antes y después de una fila seleccionada

Quiero dibujar un degradado personalizado en una fila seleccionada en un NSTableView basado en vista, mientras agrego un sutil efecto elevado. Para esto, necesito usar un color más oscuro para las líneas de cuadrícula que están antes y después de la fila seleccionada (ver here para ver un ejemplo). He pasado por alto el método drawSeparatorInRect: en NSTableRowView para dibujar la línea separadora personalizada para la fila seleccionada (usando el método isSelected como indicador), pero no puedo hacer lo mismo para la anterior/inferior (ya que dibujo la línea en la parte inferior/parte superior).

He intentado varias formas de decir a la fila más cercana que debería dibujar una línea de separación más oscura sin éxito ya que el paso de visualización no sigue el mismo orden (lo comprobé con NSLogs en el drawSeparatorInRect:, y parece que cuando te desplazas un poco esta orden cambia). Por lo tanto, a veces (principalmente después del desplazamiento) la fila no sabe que debe usar un color más oscuro ya que se dibuja antes que el seleccionado (creo que en este punto, la fila seleccionada aún no sabe que está seleccionada, de lo contrario, no entiendo lo que está pasando).

Algunas de las cosas que intenté:

  1. En el método de la fila seleccionada drawSeparatorInRect:, me han tratado de acceder a los puntos de vista hermanos ([superview subviews]) y obligar a la anterior/siguiente para dibujarse a sí mismo de nuevo.
  2. Desde la subclase NSTableView, modifique directamente la fila más cercana cuando cambie selectedIndexes.
  3. Dibujando la línea fuera de la fila seleccionada dentro de su método drawSeparatorInRect: como se muestra here.

Tenga en cuenta que hice esto tiene: una vista de primera fila preguntando si se selecciona la anterior/siguiente, un closestRowIsSelected bandera o llamando externamente un método para "forzar" el color oscuro.

Lo que tengo ahora es que la fila seleccionada dibuja los bordes superior e inferior, por lo que uno de ellos se coloca junto a la línea de la fila anterior/siguiente ... Es sutil, pero todavía está allí.

Cualquier ayuda será bien recibida.

Gracias de antemano.

! No publiqué ningún código porque el problema no existe (simplemente llama al [NSBezierPath fillRect:rect] con color rojo), creo ... así que no tengo nada que mostrar.

Respuesta

12

También he intentado esto y noté que drawSeparatorInRect: realmente solo dibuja su línea de separación inferior ya que la posición de la línea de separación superior (que es la misma que la línea de separación inferior de la fila anterior) es un píxel fuera (arriba) el clipRect de la fila.

Sin embargo, yo tengo trabajo subclasificando NSTableRowView y tener drawSeparatorInRect: de la siguiente manera:

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

este método (sólo) extraer su propia línea de separación inferior.Si es la fila seleccionada, dibujará la línea no con el color predeterminado, pero resaltada, también indicará a la fila anterior que vuelva a dibujar su línea separadora, es decir, igual a la línea superior de separación de la fila seleccionada.

Para que esto funcione, la fila sobre la fila seleccionada necesita volver a dibujar su línea de separador inferior una vez que se mueve la selección. He conseguido esto por tener este método en el delegado 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; 
} 

Este método delegado dice la fila encima de la fila aún seleccionado para volver a dibujar su línea de separación. Se llama inmediatamente antes de que la selección cambie.

+0

En realidad, la documentación de Apple resultó ser la correcta: el comportamiento predeterminado de NSTableRowView es dibujar la línea de separación en la parte inferior de la fila, no en la parte superior. He editado el ejemplo de código anterior en consecuencia. – Tim

+0

Muchas gracias, ciertamente hace lo que estaba tratando de hacer. Sin embargo, cada vez que selecciono una fila o desplazo la vista de tabla, la fila anterior a la seleccionada se redibuja varias veces, lo que produce un texto ultra audaz y otros efectos extraños. ¿Me he perdido algo? –

+0

Lo tengo funcionando perfectamente con mi código anterior. Sin embargo, moví la pieza de código que obliga a la vista de celda anterior a dibujarse, ubicada al final del método 'drawSeparatorInRect:', en un método delegado que me da la nueva fila seleccionada (utilicé 'tableView: shouldSelectRow:') . De nuevo, gracias por tu asistencia. –

Cuestiones relacionadas