Question

I have window with 3 table views (10.7.2, Xcode 4.2). They are all created in IB and NSButtonCells are connected with outlets.

I created controller class and I filled all three views with some sample data:

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
    return 10;
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn    *)aTableColumn row:(NSInteger)rowIndex {

NSButtonCell *buttonCell;

if(aTableView == dimensionTable) {    
    [dimensionButtonCell setTitle:@"Dimension"];
    buttonCell = dimensionButtonCell;
}
else if(aTableView == shopTable) {
    [shopButtonCell setTitle:@"Shop"];
    buttonCell = shopButtonCell;
}
else if(aTableView == countryTable) {
    [countryButtonCell setTitle:@"Country"];
    buttonCell = countryButtonCell;
}


return buttonCell;

}

I have 2 questions:

  1. I cannot change checkbox state through GUI. I can change it programatically, though. It blinks a bit, when you hold down mouse button, but doesn't allow change...

  2. I tried to fill data as with views, without outlets to cells. It didn't work. Are NSButtonCell cels within cell views somehow different as view based Table Views or "normal" cel based Table Views?

Was it helpful?

Solution

After long struggle I manage to find the solution for the problem. One part of the problem was simple bug at the data model side, but it wasn't crucial, something much more difficult was to be done with NSTableView delegate and datasource.

THere were mainly 3 difficulties that prevented good understanding and managing this problem:

  • apple's documentation lacks of any reasonable explanation about differences and typical usage of - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndexin table view's data source and - (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row of its delegate. While it may seem that you would need latter method, because NSButtonCells are custom NSCells it turns out it is not necessary, but I left it at the end anyway.

  • internal conversions in NSTableView methods

  • problem is not documented almost anywhere on the net

Here are steps you should do:

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {

    buttonCell = [aTableColumn dataCell];

    NSString *columnKey = [aTableColumn identifier];

    return buttonCell;

}

You can see this method has to be implemented whether you use it or not.

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {

    buttonCell = [tableColumn dataCell];

    NSString *columnKey = [tableColumn identifier];

    if(tableView == dimensionTable) {    

//        returnObject = @"Dimension";
        //        [dimensionButtonCell setTitle:@"Dimension"];
        //        buttonCell = dimensionButtonCell;
    }

    else if(tableView == shopTable) {

        [buttonCell setState:[[mySelectedShops objectAtIndex:row] integerValue]];
        [buttonCell setTitle:[myShops objectAtIndex:row]];

    }

    else if(tableView == countryTable) {

        [buttonCell setState:[[mySelectedCountries objectAtIndex:row] integerValue]];
        [buttonCell setTitle:[myCountries objectAtIndex:row]];

    }

    return buttonCell;

}

you can see I used second method, however objectValueForTableColumn could be used solely. You can also see, I have NSMutableArray mySelectedShops and mySelectedCountries to hold NSInteger (1 or 0) wrapped in NSNumber for each row in Table View.

If you set the state or integerValue of NSCell makes no difference. Both will check and uncheck NSButtonCell with values 1 or 0 of NSInteger type.

- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {

    NSString *columnKey = [aTableColumn identifier];

    if(aTableView == dimensionTable) {    
//        [dimensionButtonCell setTitle:@"Dimension"];
//        buttonCell = dimensionButtonCell;
    }
    else if(aTableView == shopTable) {

        [mySelectedShops replaceObjectAtIndex:rowIndex withObject:[NSNumber numberWithInteger:[(NSCell*)anObject integerValue]]];

    }
    else if(aTableView == countryTable) {

        [mySelectedCountries replaceObjectAtIndex:rowIndex withObject:[NSNumber numberWithInteger:[(NSCell*)anObject integerValue]]];

    }

}

Although I passed NSInteger value to NSCell object, anObject here is of __NSCFBoolean type, which means something doesn't work as expected. To be able to replace object value to arrays I have casted it to NSCell only to get integerValues. It actually works without cast as well, so it is another mystery to me, but I like it more that way.

It is clear Apple is moving to view based cells like in UITableView. Still, I hope this will help to somebody.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top