Tengo una vista basada en NSOutlineView que muestra entradas (entidad de origen) de un almacén de datos básicos. La vista en la vista de esquema utiliza un control personalizado que se implementa como una subclase de NSView. Este control muestra un marcador de color redondo basado en un valor numérico (0-7). Este valor se almacena como un atributo de la entidad de origen y está destinado a ser un método para implementar un método de etiquetado similar al de Finder.

Todo está conectado mediante enlaces con IB.

He adjuntado una captura de pantalla que, con suerte, aclarará mis intenciones.

Todo funciona bien, pero por un detalle realmente molesto. Cuando se cambia el valor numérico (desde el lado derecho de la pantalla), el control personalizado solo se actualiza cuando se cambia la selección en la vista de esquema. Obviamente, sería mejor que este cambio se reflejara de inmediato, pero hasta ahora he fallado. Probé varios escenarios con setNeedsDisplay: YES que básicamente fueron ignorados.

¿Alguna idea?

enter image description here

Editar: implementé un setter con el control personalizado:

- (void) setLabelValue: (NSNumber*) aValue {
    labelValue = aValue;
    [self setNeedsDisplay: YES];
}

Razonando que el setNeedsDisplay: desencadenaría un nuevo dibujo, en el método drawRect: consulto el valor para establecer el color adecuado:

- (void)drawRect: (NSRect) dirtyRect {
    // Label value between '1' and '7' indicate that a label was assigned. Determine label color and border color.
    if ([[self labelValue] intValue] > 0) {
        NSColor *aBackgroundColor = [NSColor clearColor];
        switch ([[self labelValue] intValue]) {
            case 1:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];
                break;
            case 2:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];        
                break;
            case 3:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];
                break;
            case 4:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];    
                break;
            case 5:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];        
                break;
            case 6:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];            
                break;
            case 7:
                aBackgroundColor = [NSColor colorWithCalibratedRed:...];        
                break;
        }
        // Draw border first.
        ...
        // Draw label color.
        ...
    } 
    // Label value of '0' indicates that no label was assigned.
    if ([[self labelValue] intValue] == 0) {
        NSBezierPath *aPath = [NSBezierPath bezierPathWithRoundedRect: ...];
        [[NSColor clearColor] set];
        [aPath fill];
    }
}
1
Roger 19 may. 2012 a las 19:17
¿No veo nada en el lado derecho de la pantalla? Muestre el código que usa cuando cambia el valor numérico.
 – 
rdelmar
19 may. 2012 a las 19:36
Si ha creado una clase de vista personalizada para mostrar el marcador de color y ha conectado elementos mediante enlaces, ¿ha implementado un enlace personalizado? ¿Cómo? ¿Seguiste la técnica descrita en Cocoa Bindings Temas de programación: ¿Cómo funcionan los enlaces?
 – 
Ken Thomases
19 may. 2012 a las 19:42
@KenThomases: No implementé enlaces personalizados. Vea mi edición para mi enfoque, obviamente, que no funciona.
 – 
Roger
19 may. 2012 a las 20:15
2
Está bien. Su -drawRect: está consultando la propiedad labelValue, pero eso solo cambia cuando se establece explícitamente en la vista . No se trata de consultar el modelo y no proporciona ninguna razón para creer que el cambio que realiza el usuario al usar el widget en la vista de detalles está configurando la propiedad de la vista de celda. Supongo que eso está ligado al modelo. Debe implementar un enlace para su vista personalizada o hacer que el controlador pase el valor cambiado a la vista de celda.
 – 
Ken Thomases
19 may. 2012 a las 20:30

1 respuesta

La mejor respuesta

Reimplementé todo usando notificaciones. No pude hacer que funcione usando enlaces. Esto es lo que hice:

El controlador de NSOutlineView (parte izquierda de la pantalla) distribuye vistas para sus elementos usando el método:

- (NSView *) outlineView: (NSOutlineView *) outlineView viewForTableColumn: (NSTableColumn *) tableColumn item: (id) anItem

Cuando se agrega una entidad asociada a un archivo (una imagen, PDF, etc.) a la vista de esquema, la vista del elemento (subclase personalizada de NSTableCellView) para ese elemento en particular registra un interés en los cambios en el labelValue propiedad de la entidad:

[[NSNotificationCenter defaultCenter] addObserver: aView selector: @selector(labelValueChanged:) name: @"LabelValueChanged" object: nil];

Cuando ocurre un cambio en la propiedad labelValue (a través de un clic en uno de los botones en la parte derecha de la pantalla), ese controlador dispara una notificación:

[[NSNotificationCenter defaultCenter] postNotificationName:@"LabelValueChanged" object:[self selectedSource]];

A través del sistema de notificación, el método labelValueChanged: es llamado por la vista del elemento (en el NSOutlineView) que invalida la visualización de los componentes de la vista personalizada que realmente dibuja la etiqueta:

- (void) labelValueChanged: (NSNotification*) aNotification {
    // A notification was received that the label was changed. Mark the label object of the receiver
    // if the object in the notification (anObject) matches the object of the receiver (objectValue).
    id anObject = [aNotification object];
    if (anObject == [self objectValue]) {
        [[self label] setNeedsDisplay:YES];
    }
}

Gracias a @KenThomases por sus sugerencias.

0
Roger 20 may. 2012 a las 21:44