0

I have an NSTableView connected to my CountViewController.h

@property (nonatomic, weak) IBOutlet NSTableView * tableCountData;

Under -(void)viewDidAppear I have code to remove all columns, except the first column, and re-create with new ones.

-(void)viewDidAppear
{
    NSArray *tableColumns = [self.tableCountData tableColumns];
    BWProject *project = ((Document *)self.view.window.windowController.document).project;

    for (NSTableColumn *col in tableColumns) {
        if ([col.identifier isEqualToString:@"columnGenes"]) continue;
        [self.tableCountData removeTableColumn:col];
    }

    for (NSString *sample in project.samples) {
        NSTableColumn *col = [[NSTableColumn alloc] init];
        col.identifier = sample;
        col.headerCell.stringValue = sample;
        [self.tableCountData addTableColumn:col];
    }

    [self.tableCountData reloadData];
}

However, when I populate the table as follows:

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    BWProject *project = ((Document *)self.view.window.windowController.document).project;
    NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];

    if (cellView == nil) {
        CGRect myRect = CGRectMake(0,0,tableColumn.width,0);
        cellView = [[NSTableCellView alloc] initWithFrame:myRect];
        [cellView addSubview:[[NSTextField alloc] initWithFrame:cellView.frame]];
    }

    if ([tableColumn.identifier isEqualToString:@"columnGenes"]) {
        cellView.textField.stringValue = [[project.geneset allKeys] objectAtIndex:row];
    } else {
        for (NSString *sample in project.samples) {
            if ([tableColumn.identifier isEqualToString:sample]) {
                BWGene *gene = [project.geneset objectForKey:[[project.geneset allKeys] objectAtIndex:row]];
                BWGeneReads *geneReads = [gene.samples objectForKey:sample];
                cellView.textField.stringValue = [NSString stringWithFormat:@"%f", geneReads.reads];
            }
        }
    }

    return cellView;
}

I get empty data columns. I have tried replacing [cellView addSubview:[[NSTextField alloc] initWithFrame:cellView.frame]] with [cellView setTextField:[[NSTextField alloc] initWithFrame:cellView.frame]] but this causes the app to crash with EXEC_BAD_ACCESS. Below is an example screenshot: Problematic NSTableView with empty columns

What am I doing wrong? I can't find any clues in the documentation but I feel like this is a simple solution as many apps use dynamic columns...

Kenneth P. Hough
  • 577
  • 2
  • 8
  • 25

1 Answers1

1

Don't do setDataCell: in a view based table view.

If you create a new NSTableCellView in viewForTableColumn, you add a NSTextField subview. You have to set textField of the cell view to this text field.

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    BWProject *project = ((Document *)self.view.window.windowController.document).project;
    NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];

    if (cellView == nil) {
        CGRect myRect = CGRectMake(0,0,tableColumn.width,0);
        cellView = [[NSTableCellView alloc] initWithFrame:myRect];
        NSTextField *myTextField = [[NSTextField alloc] initWithFrame:cellView.frame];
        cellView.textField = myTextField; // this assignment was missing
        [cellView addSubview:myTextField];
    }

    if ([tableColumn.identifier isEqualToString:@"columnGenes"]) {
        cellView.textField.stringValue = [[project.geneset allKeys] objectAtIndex:row];
    } else {
        for (NSString *sample in project.samples) {
            if ([tableColumn.identifier isEqualToString:sample]) {
                BWGene *gene = [project.geneset objectForKey:[[project.geneset allKeys] objectAtIndex:row]];
                BWGeneReads *geneReads = [gene.samples objectForKey:sample];
                cellView.textField.stringValue = [NSString stringWithFormat:@"%f", geneReads.reads];
            }
        }
    }

    return cellView;
}
Willeke
  • 14,578
  • 4
  • 19
  • 47
  • thanks for your answer. I removed the whole `setDataCell:` part and under `viewForTableColumn` I check if `NSTableCellView` returns `nil` after `makeViewWithIdentifier`. If null, I `[[NSTableCellView alloc] initWithFrame:frame]` and call `addSubview:` but I still get an empty cell, same as screenshot. (FYI: I've updated the question to reflect the changes I made.) – Kenneth P. Hough Oct 26 '17 at 12:49
  • Figured it out. Since it's a subview I can't expect `cellView.textField` to work as it's `nil`. I've updated my question to reflect what I did - idk if there is a more elegant solution but it works! Thanks again for your help! – Kenneth P. Hough Oct 26 '17 at 13:06
  • 1
    All you have to do is assign the text field to `cellView.textField`, I edited my answer. – Willeke Oct 26 '17 at 13:53
  • Wow, thanks! Can't believe I didn't make the connection there – Kenneth P. Hough Oct 26 '17 at 14:31