6

After adding a NSTableView to my xib on Xcode 4 I set it to have 4 columns. The 1st column is a simple column that will contain the name of an item. The other 3 are checkboxes. I dragged a Check Box Cell from the object library to the tableview.

I populate the table and the checkboxes get created and shown, however if I click on the nothing happens, I can't check or uncheck them. Furthermore, I don't even know how to do it by code.

How can I make this work: be able to check or uncheck the checkboxes and get their states from code.

I already saw this question and it didn't really answer my question.

Here is some of the code to take care of table, as requested:

- (int)numberOfRowsInTableView:(NSTableView *)tableView
{
    return (int)[myArray count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
{
    if([[tableColumn identifier] isEqualToString:@"col1"])
    {
       return[NSNumber numberWithInt:NSOffState];
    }    

    return [myArray objectAtIndex:row];
}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSLog(@"%d", [anObject boolValue]);
    if([[tableColumn identifier] isEqualToString:@"col1"])
    {
        NSLog(@"click col1");
    }        
    if([[tableColumn identifier] isEqualToString:@"col2"])
    {
        NSLog(@"click col2");
    }        

}

I just added more code. How do I set it to check/uncheck?

Community
  • 1
  • 1
Mr Aleph
  • 1,887
  • 5
  • 28
  • 44
  • Could you edit your question and shows us the implementation of `-tableView:setObjectValue:forTableColumn:row:`? The implementation of `-tableView:objectValueForTableColumn:row:` will help, too. –  Sep 15 '11 at 15:36
  • What kind of objects are you inserting into the array? How do you map the contents of your objects to the four columns? Your code maps the whole object to the four columns. –  Sep 15 '11 at 17:26
  • I have a array with the strings that go on the 1st column. Then the rest I am stuck. see the code I just added. – Mr Aleph Sep 15 '11 at 17:54

1 Answers1

8

The model

You need to decide upon a model, i.e., how you’re going to represent the data that’s being shown on the table view. For example:

// SomeObject.h
#import <Foundation/Foundation.h>
@interface SomeObject
@property (copy) NSString *name;
@property (assign,getter=isVisible) BOOL visible;
@property (assign,getter=isOpaque) BOOL opaque;
@property (assign,getter=isAnimatable) BOOL animatable;
@end

// SomeObject.m
#import "SomeObject.h"
@implementation SomeObject
@synthesize name, visible, opaque, animatable;
- (void)dealloc {
    [name release];
    [super dealloc];
}
@end

The nib file

For the sake of this answer, give the table columns identifiers that match the property names in SomeObject.

Providing values from the model to the table view

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
{
    // Retrieve the model object corresponding to `row'
    SomeObject *obj = [myArray objectAtIndex:row];

    // Return the object property corresponding to the column
    if([[tableColumn identifier] isEqualToString:@"name"])
    {
        return obj.name;
    }
    // Since this method has return type `id', we need to box the
    // boolean values inside an `NSNumber' instance
    else if([[tableColumn identifier] isEqualToString:@"visible"])
    {
        return [NSNumber numberWithBool:obj.visible];
    }
    else if([[tableColumn identifier] isEqualToString:@"opaque"])
    {
        return [NSNumber numberWithBool:obj.opaque];
    }
    else if([[tableColumn identifier] isEqualToString:@"animatable"])
    {
        return [NSNumber numberWithBool:obj.animatable];
    }

    return nil;
}

Using values from the table view to update the model

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    // Retrieve the model object corresponding to `row'
    SomeObject *obj = [myArray objectAtIndex:row];

    // Set the object property corresponding to the column
    if([[tableColumn identifier] isEqualToString:@"name"])
    {
        obj.name = anObject;
    }
    // Since the new value (`anObject') is an object, we need to
    // convert it to `BOOL' by sending it `-boolValue'
    else if([[tableColumn identifier] isEqualToString:@"visible"])
    {
        obj.visible = [anObject boolValue];
    }        
    else if([[tableColumn identifier] isEqualToString:@"opaque"])
    {
        obj.opaque = [anObject boolValue];
    }        
    else if([[tableColumn identifier] isEqualToString:@"animatable"])
    {
        obj.animatable = [anObject boolValue];
    }
}

It is possible to make this code simpler by using Key-Value Coding but that’s left as an exercise after you master table view data sources. :P

  • Thank you, all is well, but what is `obj`? SomeObject can be anything. If I pass `NSInteger` as row is declared then it won't work. Beyond that, i don't see how can I set a checkbox to ON or OFF (NSOffState or NSOnState) – Mr Aleph Sep 15 '11 at 18:24
  • Yeah, now i am really confused. I appreciate your help but i don't understand this at all. I mean, you saw what I was doing in [this](http://stackoverflow.com/questions/7431289/nstableview-is-not-displaying-contents-of-the-nsmutablearray) previous question. This code you just posted... well, I can't make anything out of it and I can't really see how this would even begin to help me. I really do not understand what you just wrote. I – Mr Aleph Sep 15 '11 at 18:25
  • 1
    @MrA `obj` is the object you’re inserting in the array. You can’t simply have an array of strings: where would the values corresponding to the checkboxes be stored? This is why I’ve declared a `SomeObject` class, whose instances keep one string (for the first column) and three boolean values (for the other three columns). For checkboxes that don’t have a mixed state, you can consider their on & off states as boolean values. –  Sep 15 '11 at 18:35
  • Thanks, now it more clear. So beyond the array I have to populate the table I need to declare a new object? Or can I use the array for this (NSMutableArray)? – Mr Aleph Sep 15 '11 at 18:44
  • 1
    @MrA The idea is that you have a mutable array (`myArray`) in which you store instances of a class that can represent all the four columns (one string, three boolean/integer values). In my example, the elements stored in the array are instances of `SomeObject`. Another option would be having each element in the array be an `NSDictionary`. –  Sep 15 '11 at 18:48
  • I just created a new class and added your code. It's basically a huge "cannot" or "unrecognized" or "warning". I already have an object that contains the XIB with the table. Can I add this to that? As you can see I am completelly confused. I am a C programmer, objects don't make any sense to me. – Mr Aleph Sep 15 '11 at 18:57
  • @MrA For the sake of testing, you can add that code I placed in the section ‘The Model’ inside the same implementation file (.m) that contains the table view data source. That’s not how a project is usually organised, though. As for objects, you might want to read some introduction to OOP. For the sake of this question, you can (kind of) consider them as C structures. –  Sep 15 '11 at 19:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3503/discussion-between-bavarious-and-mr-aleph) –  Sep 15 '11 at 19:14