NSMatrix con múltiples botones de alternar?

Estoy tratando de crear un NSMatrix of NSButtonCells donde se pueden seleccionar entre cero y cuatro botones (activado). Probé el siguiente código (de prueba), pero no estoy seguro de cómo puedo proporcionar la funcionalidad que necesito. Tal vez no sea posible con NSMatrix y necesito buscar un control alternativo o crear el mío propio?

@interface MatrixView : NSView
{
    NSScrollView *_scrollView;
    NSMatrix *_matrixView;
}
@end

@implementation MatrixView

- (id)initWithFrame:(NSRect)frameRect
{
    NSLog(@"initWithFrame. frameRect=%@", NSStringFromRect(frameRect));
    self = [super initWithFrame:frameRect];
    if (self != nil)
    {
        _scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, frameRect.size.width, frameRect.size.height)];
        [_scrollView setBorderType:NSNoBorder];
        [_scrollView setHasVerticalScroller:YES];
        [_scrollView setHasHorizontalScroller:NO];
        [_scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];

        NSSize contentSize = [_scrollView contentSize];
        contentSize.height = 300;

        // Make it 3 x however-many-buttons-will-fit-the-height
        CGFloat gap = 8.0;
        CGFloat width = (contentSize.width / 3.0) - (gap * 2.0);
        NSUInteger rows = (contentSize.height / (width + gap));

        NSLog(@"width=%f, rows=%lu", width, rows);

        NSButtonCell *prototype = [[NSButtonCell alloc] init];
        [prototype setTitle:@"Hello"];
        [prototype setButtonType:NSToggleButton];
        [prototype setShowsStateBy:NSChangeGrayCellMask];
        _matrixView = [[NSMatrix alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)
                                                 mode:NSListModeMatrix
                                            prototype:prototype
                                         numberOfRows:rows
                                      numberOfColumns:3];
        [_matrixView setCellSize:NSMakeSize(width, width)];
        [_matrixView setIntercellSpacing:NSMakeSize(gap, gap)];
        [_matrixView setAllowsEmptySelection:YES];
        [_matrixView sizeToCells];
        [_scrollView setDocumentView:_matrixView];
        [self addSubview:_scrollView];
        [self setAutoresizesSubviews:YES];
        [prototype release];
    }

    return self;
}

...

preguntado el 22 de mayo de 12 a las 19:05

Sin duda, puede tener una matriz con varios botones de alternar: hice uno en IB, con NSButtonCells (presione sobre el tipo de empuje) y la matriz en modo resaltado. Esto mostró botones que permanecieron resaltados hasta que los presionó nuevamente. Limitarlo a 4 solo es un poco más complicado: aún no lo he descubierto por completo. -

@rdelmar Acabo de cambiar el código anterior para usar los botones push-on-push-off y para poner la matriz en modo de resaltado, pero no funciona como se desea (el modo push-on-push-off está anulado por la matriz y nada se queda empujado). ¿Había algo más que necesitaba ser configurado? -

1 Respuestas

Conseguí que esto funcionara con la siguiente subclase de NSMatrix. Agregué una propiedad, onCount, para realizar un seguimiento de cuántos botones estaban activados:

@implementation RDMatrix
@synthesize onCount;

-(id) initWithParentView:(NSView *) cv {
    NSButtonCell *theCell = [[NSButtonCell alloc ]init];
    theCell.bezelStyle = NSSmallSquareBezelStyle;
    theCell.buttonType = NSPushOnPushOffButton;
    theCell.title = @"";
    if (self = [super initWithFrame:NSMakeRect(200,150,1,1) mode:2 prototype:theCell numberOfRows:4 numberOfColumns:4]){ 
        [self setSelectionByRect:FALSE];
        [self setCellSize:NSMakeSize(40,40)];
        [self sizeToCells];
        self.target = self;
        self.action = @selector(buttonClick:);
        self.drawsBackground = FALSE;
        self.autoresizingMask = 8;
        self.allowsEmptySelection = TRUE;
        self.mode = NSHighlightModeMatrix;
        self.onCount = 0;
        [cv addSubview:self];
        return self;
    }
    return nil;
}


-(IBAction)buttonClick:(NSMatrix *)sender {
    NSUInteger onOrOff =[sender.selectedCells.lastObject state];
    if (onOrOff) {
        self.onCount += 1;
    }else{
        self.onCount -= 1;
    }
    NSLog(@"%ld",self.onCount);
    if (self.onCount == 5) {
        [sender.selectedCells.lastObject setState:0];
        self.onCount -= 1;
    }    
}

Cuando intente seleccionar el quinto botón, parpadeará, pero luego se apagará. Esto podría ser un problema dependiendo de cómo esté usando el estado de estos botones. Los acabo de registrar con este método:

-(IBAction)checkMatrix:(id)sender {
    NSIndexSet *indxs = [self.mat.cells indexesOfObjectsPassingTest:^BOOL(NSButtonCell *cell, NSUInteger idx, BOOL *stop) {
        return cell.state == NSOnState;
    }];
    NSLog(@"%@",indxs);
}

Después de editar: no me gustó la forma en que mi primer método encendió el botón brevemente antes de apagarlo nuevamente cuando intenta hacer clic en el quinto botón. Encontré lo que creo que es una mejor solución que consiste en anular mouseDown en la subclase de matriz (si desea probar esto, debe eliminar las declaraciones setAction y setTarget y eliminar el método buttonClick):

-(void)mouseDown:(NSEvent *) event {
    NSPoint matPoint = [self convertPoint:event.locationInWindow fromView:nil];
    NSInteger row;
    NSInteger column;
    [self getRow:&row column:&column forPoint:matPoint];
    NSButtonCell *cell = [self cellAtRow:row column:column];
    if (self.onCount < 4 && cell.state == NSOffState) {
        cell.state = NSOnState;
        self.onCount += 1;
    }else if (cell.state == NSOnState) {
        cell.state = NSOffState;
        self.onCount -= 1;
    }
}

contestado el 24 de mayo de 12 a las 01:05

@trojanfoe: No estaba satisfecho con el método que usé para limitar la cantidad de botones que pueden estar activados, así que se me ocurrió lo que creo que es una mejor solución. Ver mi respuesta editada. - rdelmar

No se preocupe, he usado un código de conteo diferente de todos modos, deshabilitando los botones no seleccionados cuando se seleccionan 4. La clave de su respuesta es el uso del método de destino y descubrir qué botón se acaba de presionar. - troyano

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.