Using a real view in a Table cell
Using a real view in a Table cell
- Subject: Using a real view in a Table cell
- From: email@hidden
- Date: Fri, 25 Apr 2008 10:21:47 +0200
Hi,
I need to have something that behaves like a table where each cell
could be a quite complex view with standard controls and sub views
etc. It needs to run on 10.4 and above, so NSCollectionView is not an
option.
I seem to have two choices:
1. Implement my own custom view that is independent of NSTableView
that allows subviews to be stacked on top of each other and maintains
it own table-like behaviours (selections, column dragging etc).
2. Use an NSTableView and massage each cell into being a view.
Being adventurous, I tried option 2 first to see what I could get for
free and have come up with something that seems to work.
An example is available at http://idisk.mac.com/mattg/Public/ViewCell.zip
To summarize, I use a custom column subclass which implements:
- (id)dataCellForRow:(int)row
{
NSView* view = [delegate viewForColumnIdentifier:[self identifier]
row:row];
ViewCell* cell = [[ViewCell alloc] initWithView:view];
return cell;
}
and a custom cell class:
@interface ViewCell : NSCell
{
NSView* _view;
}
-(id) initWithView:(NSView*)view;
-(void) setView:(NSView*)view;
-(NSView*) view;
@end
@implementation ViewCell
-(id) initWithView:(NSView*)view
{
if ((self = [super initImageCell:nil]) != nil)
[self setView:view];
return self;
}
-(void) dealloc
{
[self setView:nil];
[super dealloc];
}
-(void) setView:(NSView*)newView
{
if (newView != _view)
{
[_view release];
_view = [newView retain];
}
}
-(NSView*) view
{
return _view;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView
*)controlView
{
NSView* view = [self view];
if (!view)
return;
if (![view superview])
[controlView addSubview:view];
NSRect oldFrame = [view frame];
if (!NSEqualRects(oldFrame, cellFrame))
{
// [controlView setNeedsDisplayInRect:oldFrame]; // Not needed?
[view setFrame:cellFrame];
}
}
@end
There is also a controller which is the table's delegate and
datasource and knows how to get the real view for a cell
@implementation AttributesController
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 2; // The sample app only does 2 rows
}
-(NSView*) viewForColumnIdentifier:(id)identifier row:(int)row
{
NSView* result = nil;
if ([identifier isEqualToString:@"attributes"])
{
result = row == 0 ? attributesView : attributesView2;
}
return result;
}
- (float)tableView:(NSTableView *)tableView heightOfRow:(int)row
{
NSView* view = [self viewForColumnIdentifier:@"attributes" row:row];
float result = NSHeight([view bounds]);
return result;
}
As you can see, drawInteriorWithFrame is being quite sneaky. It is
adding the real view associated with the cell as a subview of the
parent table view. The cell itself never does any drawing, it just
keeps the location of these extra views in sync with the cells they
represent.
However all of this cleverness set off two alarm bells:
1. This looks a bit fragile and maybe some future update to
NSTableView will break this.
2. Whenever I think I am being far too cunning it usually means I have
overlooked a much simpler way to do what I want.
Does anyone else have any suggestions
Thanks
Matt Gough
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden