PDA

View Full Version : Getting started with NSTableView




Thomas Harte
Jan 20, 2006, 03:50 PM
I am someone with past experience of C++ and MFC who is trying to get started with Objective-C and Cocoa development. I have some books ordered to help me, but they haven't turned up yet, so I'm stuck trying to figure stuff out from the XCode help and http://developer.apple.com/documentation/Cocoa/. I did the Currency Converter tutorial and now am sort of wandering the API around aimlessly.

Today I am trying to make a decent stab at a NSTableView. I have added an NSTableView to my .nib, and set my controller as a dataSource. I have added the two methods numberOfRowsInTableView and what I guess could be called objectValueForTableColumn to my controller and I am able to populate the NSTableView by returning sensible results from those two methods. I am returning NSStrings for objectValueForTableColumn.

I have two questions. Firstly, what is the "correct" way to use the value passed as an (NSTableColumn *) to objectValueForTableColumn? At the minute I'm just doing [[tableColumn headerCell] stringValue] and comparing that to what I know are the column headers. That works, but strikes me as a very roundabout way of doing things and prone to localisation problems.

Secondly, how do I stop my NSTableView from being editable? What I really want is to receive a message on a row double click that will be responded to by actions in my model class. I have not implemented setObjectValue, which I thought would be enough to prevent editing but it doesn't seem to be. I want dragging and dropping so I need to implement validateDrop and forDraggedRowsWithIndexes, but I haven't done that yet.

Thanks in advance, and sorry for asking what are probably very basic questions that will have easy and easily discoverable answers once I have books.



HexMonkey
Jan 20, 2006, 04:09 PM
Firstly, what is the "correct" way to use the value passed as an (NSTableColumn *) to objectValueForTableColumn? At the minute I'm just doing [[tableColumn headerCell] stringValue] and comparing that to what I know are the column headers. That works, but strikes me as a very roundabout way of doing things and prone to localisation problems.

You could use [tableColumn identifier] instead. The identifier is set in Interface Builder in the same place as the header title, and it needn't be localised.

Secondly, how do I stop my NSTableView from being editable? What I really want is to receive a message on a row double click that will be responded to by actions in my model class. I have not implemented setObjectValue, which I thought would be enough to prevent editing but it doesn't seem to be.

To prevent the cells from being editable, select each table column in Interface Builder and uncheck the "Editable" attribute in the inspector.

To handle a double click, add the following code in your awakeFromNib method:
[tableView setTarget:self];
[tableView setDoubleAction:@selector(doubleClickInTable:)];

The doubleClickInTable method (call it anything you want) would be implemented as follows:

- (void)doubleClickInTable:(id)sender
{
int rowIndex = [sender selectedRow]; //Use selectedRowIndexes if you're supporting multiple selection

//Handle the double click
}

robbieduncan
Jan 20, 2006, 04:11 PM
I would recommend looking at Bindings instead of a datasource but we'll skip that for now!

Set a tag for each header in Interface Builder and then use [tableColumn tag]==0 (or whatever the tag value is: they are ints). The tag won't change on localization. (and int comparisons are cheaper than NSString). Edit: beaten to it and with the correct answer too: columns don't seem to have tags :(

Per column (double click on the column until it highlights) there is an editable attribute in Interface Builder. Use that to stop it being editable :D

Any more questions?

Thomas Harte
Jan 21, 2006, 10:34 AM
To handle a double click, add the following code in your awakeFromNib method: ...
I have implemented it exactly as you suggest, but I seem to be getting single clicks as well. Is there anything I can do about that?
I would recommend looking at Bindings instead of a datasource but we'll skip that for now!
We'll have to as I haven't yet figured out anything whatsoever about Bindings! I'll make a note to check that topic out as soon as I have some nice tangible documentation though.
You could use [tableColumn identifier] instead.
Set a tag for each header in Interface Builder and then use [tableColumn tag]==0 (or whatever the tag value is: they are ints)
I've gone with naming my columns as numbers and the following:

int column = [[tableColumn identifier] UTF8String][0] - '0';

I'm only planning on three columns, so I don't have to worry about moving on from '9' to ';' or anything like that.

robbieduncan
Jan 21, 2006, 10:38 AM
We'll have to as I haven't yet figured out anything whatsoever about Bindings! I'll make a note to check that topic out as soon as I have some nice tangible documentation though.

Start off with the Apple Documentation (http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/CocoaBindings.html).

That will probably leave you dazed and confused so then take a look at a nice easy introductory tutorial (http://cocoadevcentral.com/articles/000080.php).

Now you are probably beginning to get an understanding and some clear examples (http://homepage.mac.com/mmalc/CocoaExamples/controllers.html) will help.

HexMonkey
Jan 21, 2006, 02:32 PM
I have implemented it exactly as you suggest, but I seem to be getting single clicks as well. Is there anything I can do about that?

That's strange, the only way that happens for me is if the table view also has an action (as well as a double action). Try adding the code:
[tableView setAction:nil];
to the end of your awakeFromNib method and see if it fixes it. If it does, check your connections in Interface Builder and make sure you're not calling setAction elsewhere in your code.

Thomas Harte
Jan 21, 2006, 06:00 PM
Start off with the Apple Documentation.
Although I am building on 10.4, I want to retain compatibility with 10.2 and 10.3 so I guess I can't use bindings in this project. It's actually really trivial on the code side and something I'm sure anyone with good Cocoa sense could knock up in half an afternoon. If it gets too much for me I'll just go back to the tutorials rather than asking stupid questions here...
That's strange, the only way that happens for me is if the table view also has an action (as well as a double action). Try adding the code: ...
Interestingly that stopped the response to double clicks, so I guess I must have a connection set up in Interface Builder that I've just forgotten about. I can't find anything, but I'm still not 100% confident with that corner of the developer tools having just been using XCode to do the normal platform neutral stuff with SDL and so on until now.

Anyway, I just wanted to say thanks to both of you for the help. Thanks!