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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to