Question

I have a small NSTableView with a checkbox. Whenever the checkbox is not checked, I want one of the adjacent NSCells to be grayed out and inaccessible.

However, I can't figure out how to address only one specific cell. -dataCellForRow of NSTableColumn always changes the template cell for the whole table column.

How can I access one single cell?

Edit: I fill the table view using the NSTableViewDataSource protocol.

Was it helpful?

Solution

You don't "access a cell". NSTableView asks for data only when necessary, you don't populate it or control it directly.

Instead, you create a controller object which implements the NSTableViewDatasource and optionally NSTableViewDelegate protocols. The table view then sends the datasource messages to your controller and your controller supplies the appropriate data.

You can allow editing for an object displayed in the table view by implementing the ‑tableView:setObjectValue:forTableColumn:row: datasource method. This method will be called on your controller object when the user clicks the checkbox. It is your controller's responsibility to update the model appropriately.

When the model is updated, your controller should tell the table view to reload. The table view will then ask your controller for the value of any cell that requires display using the ‑tableView:objectValueForTableColumn:row: datasource method. This will include the cell that you need to disable. Your controller needs to supply the appropriate value for the cell.

If you need more control of the cell, you can implement the ‑tableView:willDisplayCell:forTableColumn:row: delegate method. This is called just before a cell is displayed, and you can modify the cell appropriately.

More info about using data sources is in the docs.

The other option (instead of using a datasource) is to use Cocoa Bindings and an NSArrayController that you bind to your collection of model objects. In that case, you can bind the Enabled binding of the table column to some property of your model object that controls the cell's enabled state. It is your responsibility to ensure that the state of that property is correct.

If you need to make the property dependent on the value of another property, you can use the dependent key mechanism outlined in the Key-Value Observing documentation.

OTHER TIPS

Could you bind the editability of that column to the value that is being displayed in the checkbox? i.e. if it is checked, it is editable, otherwise it isn't?

I am trying to remember the exact editor interface, and I am not next to my Mac at home, so I am not able to do a total walk through on it - hope this can point you in the right direction.

Since SDK Version 10.7, there's -viewAtColumn:row:makeIfNecessary: on NSTableView. The majority of information I found on the web don't take the new methods into account, so here it is for all the others looking for an answer to this question.

From Mouse Event to Cell Selection

First, add a protocol for your controller to handle cell selection from a table view, like this:

@protocol XYZCellSelectionDelegate <NSObject>
- (void)cellViewWasSelectedAtRow:(NSInteger)row column:(NSInteger)column;
@end

Then subclass NSTableView and override -mouseDown:

// In your Custom Table View subclass:
- (void)mouseDown:(NSEvent *)event
{
    NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
    NSInteger selectedRowIndex = [self rowAtPoint:point];
    NSInteger selectedColumnIndex = [self columnAtPoint:point];

    if ([self.calendarViewDelegate respondsToSelector:@selector(cellViewWasSelectedAtRow:column:)])
    {
        [self.calendarViewDelegate cellViewWasSelectedAtRow:selectedRowIndex column:selectedColumnIndex];
    }

    [super mouseDown:event];
}

Afterwards, you can use -viewAtColumn:row:makeIfNecessary: like this in the delegate/controller object:

- (void)cellViewWasSelectedAtRow:(NSInteger)row column:(NSInteger)column
{
    NSView *selectedView = [self.tableView viewAtColumn:column row:row makeIfNecessary:YES];

    // Do something with the cell to the right
    NSInteger nextColumn = column + 1;
    NSView *cellNextToIt = [self.calendarTableView viewAtColumn:nextColumn row:row makeIfNecessary:YES];

}

Note: Nowadays, I'd pass the table view to the delegate as a parameter instead of relying on the delegate to keep a reference to the table view.

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