0
votes

I'm trying to set up a table view where on column is a list of strings and another column is a list of checkboxes for each element in the first column. I think I'm fundamentally misunderstanding how to implement the various methods in the NSTableView protocol. Please note that any provided solutions do not need to support legacy versions of OSX.

Below is my implementation. Note that my tableView has 2 columns, where the first column (and cells) have an identifier called "myCell". The second column (and cells) have an identifier called "checkBoxCell". My first column is behaving as expected, where each element in my array is mapped to a row in the first column. However, when I try to create my checkBoxCell via makeViewWithIdentifier:owner, my whole table view becomes a sort of see through and I can see all my stuff on my desktop. I don't know why this is. You can see in my else statement the cluster of different things I have tried to get the checkboxes to be checked, but to no avail. My questions can be boiled down to this.

1) Why is my tableview "see through" when using makeViewWithIdentifier:owner

2) What is the proper paradigm for allocating cells in a table view? How can I tweak my code to accomplish this?

Here is my header for my delegate.

#import <Cocoa/Cocoa.h>

@interface BMAppDelegate : NSObject <NSApplicationDelegate,NSTableViewDataSource,NSTableViewDelegate>

@property(nonatomic,strong)NSMutableArray* schemes;
@property(nonatomic,strong)NSMutableArray* checkedStates;


@property (assign) IBOutlet NSWindow *window;

@property (weak) IBOutlet NSButtonCell *buildButton;
@property (weak) IBOutlet NSTableView *schemeTableView;
@property (weak) IBOutlet NSButtonCell *buildCheckBox;

@property (nonatomic, strong) __block NSTask *buildTask;
@property (nonatomic) BOOL isRunning;
@property (nonatomic, strong) NSPipe *outputPipe;

@end

Here is my implementation.

#import "BMAppDelegate.h"
#import "BMSchemeHandler.h"

@implementation BMAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
      self.schemes = [BMSchemeHandler parseSchemeFileToArray];
    self.schemeTableView.dataSource=self;
    self.schemeTableView.delegate=self;
    self.checkedStates=[[NSMutableArray alloc]init];



}

-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
    return (self.schemes.count);
}

-(void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
    if([tableColumn.identifier isEqualToString:@"buildCheckBox"]){
        [self.checkedStates insertObject:[NSNumber numberWithInt:[object intValue]] atIndex:row];
        [self.buildCheckBox setState:[[self.checkedStates objectAtIndex:row] intValue]];
    }

    [tableView reloadData];
}


-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
   if([tableColumn.identifier isEqualToString:@"myCell"]){ //first column
       NSTextFieldCell* cell=[[NSTextFieldCell alloc]initTextCell:[self.schemes objectAtIndex:row]];
        return cell;
   }else{ //2nd column
   //NSButtonCell* cell=[tableView makeViewWithIdentifier:@"buildCheckBox" owner:self];
  // NSButtonCell* checkBox=[[NSButtonCell alloc]init];
   // self.buildCheckBox=[[NSButtonCell alloc]init];
   //self.buildCheckBox=[tableView makeViewWithIdentifier:@"buildCheckBox" owner:self];
   // [cell setState:[[self.checkedStates objectAtIndex:row] intValue]];
   //
  [self.buildCheckBox setState:[[self.checkedStates objectAtIndex:row] intValue]];
   return self.buildCheckBox;
   }
    return nil;
}

Here is my layout in interface builder. enter image description here

Here is my "see through" table, usually it shows the code in xcode behind the window, but it took on this form after snagging a screenshot of it. enter image description here

1

1 Answers

0
votes

If you're doing it without bindings, you need to implement the NSTableViewDelegate method tableView:viewForTableColumn:row: In it you will dequeue an NSTableCellView with the identifier buildCheckBox for the appropriate column, and do your state assignment there, and return the modified NSTableCellView instance so that the table can display it.

The NSTableViewDatasource protocol is just providing the table a value for each row/col index in the matrix. It is also called when the user modifies the data in the table, so that the corresponding source data can be changed. That's what setObjectValue should be doing-- just updating the object instance that corresponds to the cell that the user changed. Similarly 'objectValueForTableColumn:row` is just going to return an NSString or and NSNumber(the bool) for your table.

NSTableViewDelegate is what the table calls to get the appropriate subviews, and if you implement tableView:viewForTableColumn:row: you can change the state of the subviews of the cell.

If you were to use bindings, you could bind the state of the checkbox to the table view's objectValue. Meaning you could skip the delegate method that modifies the view. And if you were to use an array controller, you could likewise skip the datasource methods that provide objectValue for each cell.