Re: While on the subject of: NSOutlineView
Re: While on the subject of: NSOutlineView
- Subject: Re: While on the subject of: NSOutlineView
- From: Andreas Mayer <email@hidden>
- Date: Wed, 30 Jul 2003 16:25:53 +0200
Am Mittwoch, 30.07.03 um 07:32 Uhr schrieb April Gendill:
The coverage of table and outline views is at best, brief.
That's probably because it's not that difficult, really.
Table and outline views might as
well be molecular biology as far as I'm concerned.
I have absolutely no idea how they work...
If you read all those sources, you should. :) There's even a nice
picture in "Learning Cocoa".
because the compiler tells me what I can
see as plain as day, that the functions return nothing, do nothing, are
useless. one of them declares a variable that never gets used,
That does not sound like a problem with NSTableView. More like a
problem with (Objective-)C in general.
I would sell my first born for a "for dummys" level explanation of
outline and table views. How they work, how to manipulate the data, and
most of all how to drag an item in a table view from one position to
the next without it making a copy.
Well, that's three different things:
1. how to display data in a table view
2. how to edit data through a table view
3. how to drag-order rows of a table view
I will try to help with 1. and 2. - didn't do 3., so no help there (I
will have to do that myself soon, though).
1. You need to understand that an NSTableView does not hold any data.
So this
All i need to do is take a dictionary, put it in a view
is not how it works. You _don't_ 'put data in a table view'.
Instead, you just tell the table view, whom to ask if it needs to
(re)display any row/column:
[tableView setDataSource:myDataSource];
Then the table view will eventually want to know how many rows it will
have to handle. It sends:
[myDataSource numberOfRowsInTableView:self];
And your data source will have to answer with an integer:
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return numberOfRows;
}
Whenever the table view needs to display some field (a single column of
a single row) it sends:
[myDataSource tableView:self objectValueForTableColumn:theTableColumn
row:theRow];
Note that 'theTableColumn' is _not_ an integer, but an object of type
NSTableColumn. You can identify it by sending
[theTableColumn identifier];
(You set the identifier in Interface Builder. Double click the table
view, click the column and edit 'Identifier' in the 'Attributes' tab of
the 'Show Info' panel.)
Now in your data source, you will have to find the object to be display
in row 'theRow' and return the part of it you want to be displayed in
column 'theTableColumn':
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
...
someObjectForRow = (... find object for row 'rowIndex' ...)
someObjectForColumn = (... find value to display in 'aTableColumn'
...)
return someObjectForColumn;
}
These two methods, numberOfRowsInTableView: and
tableView:objectValueForTableColumn:row:, are all you need to
implement, to display data in a table view.
2. If you want the table view to be able to _alter_ your data, you need
to implement one more method. Every time, the user has changed a value
in a table view, the table view will send this to its data source:
[myDataSource tableView:self setObjectValue:newValue
forTableColumn:theTableColumn row:theRow];
So you implement:
- (void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject forTableColumn:(NSTableColumn
*)aTableColumn row:(int)rowIndex
{
...
someObjectForRow = (... find object for row 'rowIndex' ...)
(... find out which attribute corresponds to aTableColumn ...)
[someObjectForRow setValueForSomeAtttribute:anObject]
}
That's all there is about table views and data sources. If you need to
implement drag and drop, look at the
tableView:acceptDrop:row:dropOperation:,
tableView:validateDrop:proposedRow:proposedDropOperation: and
tableView:writeRows:toPasteboard: data source methods.
Now back to your specific problem.
All i need to do is take a dictionary, put it in a view and let a user
manitpulate it
Well, that's a bit of a problem. There is no inherent order of objects
inside a dictionary. But for a table view data source, you will need to
know which objects to display for which row. So either you use the row
numbers as keys for the dictionary (not all that efficient) or you need
to maintain the order of objects somewhere else; in an NSArray for
instance.
Since this takes an outline view and I
have given up any hope of grasping them
Outline views are really not _that_ different from table views. For
finding the values to be displayed, they basically use the same method
as do table views, only that they do this for each 'parent' object.
So instead of numberOfRowsInTableView: you implement
outlineView:numberOfChildrenOfItem:
and have to tell the outline view, how much children the asked-for item
has.
Similar with tableView:objectValueForTableColumn:row: - you implement
outlineView:child:ofItem:
_and_
outlineView:objectValueForTableColumn:byItem:
instead.
In outlineView:child:ofItem: you tell the outline view which child
object is at the asked-for index (ofItem: denotes the parent item).
outlineView:objectValueForTableColumn:byItem: asks a item for the value
to be displayed in a single column of the outline view.
To handle changes, your data source needs to implement
outlineView:setObjectValue:forTableColumn:byItem:
I thought hmm maybe if I took a
table view for the root of each dictionary, and when a user clicked the
root item, in a second table view object they would see the dictionary
contents(and be able to change them)
Sounds like the right task for an outline view:
- (int)outlineView:(NSOutlineView *)outlineView
numberOfChildrenOfItem:(id)item
{
int result = 0;
if ([item isKindOfClass:[NSDictionary class]]) {
result = [(NSDictionary *)item count];
}
return result;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index
ofItem:(id)item
{
// note that NSDictionary.allValues does not promise any particular
order of the objects,
// so you may want to do something more specific (actually, you
_should_ :))
return [[(NSDictionary *)item allValues] objectAtIndex:index];
}
- (id)outlineView:(NSOutlineView *)outlineView
objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
... now, here you need to find the value to be displayed for item
'item' in column 'tableColumn' ...
return <some value>;
}
This should do it, basically.
Disclaimer: Code typed in Mail.app, so beware. :)
bye. Andreas.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.