Getting checkboxes to reflect their state in an NSTableColumn

912 views Asked by At

I'm making this program that has an NSTableView with four columns, two of which are make of checkboxes. I'm only trying to get one working right now and I've gotten stuck.
First, here's my relevant code:

    - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { 

    NSString *filePathThree = [[NSBundle mainBundle] pathForResource:@"mydictionary" ofType:@"plist"];
    NSData *myDataThree = [[NSData alloc]initWithContentsOfFile:filePathThree];
    self.flozzCodeAndName = (NSMutableDictionary *)[NSPropertyListSerialization
                                                    propertyListFromData:myDataThree
                                                    mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                    format:NULL
                                                    errorDescription:NULL];

    return [[flozzCodeAndName objectForKey:@"name"] count];
} 

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

    NSButtonCell *cell;
    cell = [[NSButtonCell alloc] init];
    [cell setButtonType:NSSwitchButton];
    [cell setTitle:@""];
    [cell setTag:rowIndex];
    NSLog(@"%d", [cell tag]);
    [cell setCellAttribute:NSCellEditable to:3];
    [cell setImagePosition:NSImageOnly];
    [cell setState:NSOnState];

    NSLog(@"%d", [cell state]);
    [havzColumn setDataCell:cell];
    [myTableVeew reloadData];
    [cell release]; 

}




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

    NSString *filePathThree = [[NSBundle mainBundle] pathForResource:@"mydictionary" ofType:@"plist"];
    NSData *myDataThree = [[NSData alloc]initWithContentsOfFile:filePathThree];
    self.flozzCodeAndName = (NSMutableDictionary *)[NSPropertyListSerialization
                                                    propertyListFromData:myDataThree
                                                    mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                    format:NULL
                                                    errorDescription:NULL];

    NSArray *myArray = [flozzCodeAndName objectForKey:[aTableColumn identifier]];

    NSString *myStringValue = [myArray objectAtIndex:rowIndex];

    return myStringValue;
}

As you can see, I'm using the data source method for this table rather than bindings. The book I read for Cocoa made some checkboxes with tags, but I think they were in an array, so that might not be the best thing to do.

Anyway, when I run this, the debugger will show me the tag (which equals the row) along with the state of the button (1 for all of them because of NSOnState). My problem is that I cannot get the boxes to check and uncheck depending on their state. I read this question: Checkbox on table column won't register click

And then the NSTableView datasource reference. According to Mr. Nozzi in the linked question, it seems to me that an array containing the states for the boxes is needed, so I tried that, setting [cell state] to an NSNumber to get it into an NSMutableArray. I FUBAR'd that and don't think that was right. There are 454 rows in this table (tags go to 453 because of arrays starting at 0), for all four columns.

I also wonder if I should put the cell definition stuff that is in tableview:setObjectValue: into an 'awakeFromNib'. I did put a checkbox button cell in the IB, but I was having problems with it earlier, so I decided to do it programmatically too. During all of these, I did, and still do, have a [myTableVeew reloadData] in the setObjectValue method.

The assistance is appreciated, if any other info is needed, I can get it.

1

There are 1 answers

0
Joshua Nozzi On

You have two problems: Your data source keeps getting blown away and you're not using the ...objectValue... method properly.

Data Source: You're blowing away your data source in your -numberOfRowsInTableView: method and replacing it every time the table needs to do a refresh. You'll want to cache (a mutable copy of) your dictionary only when you need to (like at application launch) then only refer to it from the table data source methods. Perhaps you should move it to an instance variable and use proper accessors.

Also, the documentation mentions that, because the data source methods are called very frequently, they should be fast, so from a performance viewpoint alone this is not a good idea. You should only do what it takes to answer the question the delegate method is posing to keep the table responsive with large data sets.

Object Value: You should ONLY be returning the object value from this method (usually an NSNumber object containing the state the checkbox is meant to toggle.

You should set your table column's -dataCell when the view is loaded or at application launch. Even easier: drag a check box cell into the table column in Interface Builder to set that as the data cell without code.

Additional Observation: If you plan to persist the changes to this information in any way, note that you must never rely on the application bundle being writable and should never attempt to overwrite resource files like the one you're loading from your bundle. You'll need to save the information elsewhere, using your bundle copy as a template copy only.