Cocoa NSTableView, NSTextFieldCell, NSCell, ImageAndTextCell tutorial

298 篇文章 2 订阅

http://juliuspaintings.co.uk/cgi-bin/paint_css/animatedPaint/070-NSTableView-ImageAndTextCell.pl

70: Display an NSTextfieldCell containing text and an image within a NSTableView

Problem: We want to display a table of rows of text and image pairs. NSTableView looks like the ideal display context but there is no specific NSCell type dedicated to this kind of task. The text is to be editable and the means provided for the user to delete a selected row, insert a new row at a selected row or at table end
NSTableView using NSTextFieldCell, NSCell, ImageAndTextCell exaple

Example NSTableView using NSTextFieldCell and ImageAndTextCell

Answer: We make use of Apple's ImageAndTextCell Class that is to be found in Apple's SourceView example.

The key idea is straightforward. Subclass NSTextViewCell as the class ImageAndText (Apple example: ImageAndTextCell.h,ImageAndTextCell.m). This class will intercept the call to NSTextViewCell's drawWithFrame:inView: method and use it to draw the image before passing control on to super' drawWithFrame:inView: which will draw the text.

One thing to remember is that the same ImageAndText object is used to display each of the text and image pairs. Essentially one can think of ImageAndText being moved through successive rows drawing as it goes.

In Interface Builder declare your control to be both the NSTableView's delegate and data source.

As delegate declare methods for:

  • the obligatory pair of -(NSInteger)numberOfRowsInTableView:,
    and -(id)tableView:objectValueForTableColumn:row:

  • Then the method for putting the data into the cell 
    -(void)tableView:willDisplayCell:forTableColumn:row:

  • and that for putting the returned edited text back into the database
    -(void)tableView:setObjectValue:forTableColumn:row:

  • For reasons I have yet to determine one also needs to declare
    - (NSCell *)tableView:dataCellForTableColumn:row:

A curiosity

There are occasions on which one needs to tell NSTableView to end editing. For instance, if one has clicked on the text in one of the rows and started editing and then without doing anything else one clicks on the AddAtSelectedRow key, it is necesary to tell NSTableView to stop editing or the edit will appear in the newly inserted row.

The only approach I've so far found to work was presented inhttp://www.stone.com/The_Cocoa_Files/Takes_All_Sorts.html.

This consists of returning focus to the NSTableView window. See the addAtSelectedRow method below. This preserves the original edit. To abort the edit completely use the NSTableView method abortEditing.

Source code

    //

    //  ImageAndTextCell.h

   //

    //  Copyright  2006, Apple. All rights reserved.

    //  JJG: edited to remove memory management statements

    //  and for this example inessential code.

    

#import <Cocoa/Cocoa.h>

    

   @interface ImageAndTextCell : NSTextFieldCell {

    @private

        NSImage*nsImageObj;

    }

   @property (assign) NSImage*nsImageObj;

    

    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;

    

    //- (NSSize)cellSize;

    

   @end

    

    

    

    

    // ImageAndTextCell.m

    // Copyright  2006, Apple Computer, Inc., all rights reserved.

   //

    // Subclass of NSTextFieldCell which can display text

    //  and an image simultaneously.

    //  JJG: edited to remove memory management statements

    //  and for this example inessential code.

    

#import "ImageAndTextCell.h"

    

   @implementation ImageAndTextCell

   @synthesize nsImageObj;

    

    - (id)copyWithZone:(NSZone *)zone {

        ImageAndTextCell *zCell = (ImageAndTextCell *)[super copyWithZone:zone];

        zCell.nsImageObj =self.nsImageObj;

       return zCell;

    }  // end copyWithZone

    

    

    

    // over-ride NSCell selectWithFrame :

    // called when frame is selected for editing

    - (void)selectWithFrame:(NSRect)aRect

inView:(NSView *)controlView

editor:(NSText *)textObj

delegate:(id)anObject

start:(NSInteger)selStart

length:(NSInteger)selLength {

NSLog(@"My Cell: selectWithFrame");

    NSRect textFrame, imageFrame;

    NSDivideRect (aRect, &imageFrame,&textFrame,

                 3+[nsImageObj size].width,NSMinXEdge);

    [super selectWithFrame: textFrame

                    inView: controlView

                    editor:textObj

                  delegate:anObject

                     start:selStart

                    length:selLength];

}

    

    // draw the image on the left hand side of the NSTextFieldCell

    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {

       if (nsImageObj == nil) {

            [super drawWithFrame:cellFrame inView:controlView];

           return;

        }// end if

        

        NSSizeimageSize;

        NSRectimageFrame;

        //NSRecttextFrame;

        

        imageSize = [nsImageObj size];

        NSDivideRect(cellFrame,&imageFrame,&cellFrame,

                    3+imageSize.width,NSMinXEdge);

       if ([self drawsBackground]){

            [[self backgroundColor] set];

            NSRectFill(imageFrame);

        }// end if

        imageFrame.origin.x +=3;

        imageFrame.size = imageSize;

        

       if ([controlView isFlipped]) {

            imageFrame.origin.y += ceil((cellFrame.size.height+

                                         imageFrame.size.height)/2);

        }else {

            imageFrame.origin.y += ceil((cellFrame.size.height-

                                         imageFrame.size.height)/2);

        }// end if

        

        [nsImageObj compositeToPoint:imageFrame.origin

                           operation:NSCompositeSourceOver];

        

        [super drawWithFrame:cellFrame inView:controlView];

        //[super drawWithFrame:textFrame inView:controlView];

    }

    

    

   @end

    

    

    

   //

    //  MyController.h

    //  TableViewExample

    

#import

    //@class MyNSCell;

   @class ImageAndTextCell;

    

    

   @interface MyController : NSObject {

        

        NSMutableArray * nsMutaryOfMyData;

        ImageAndTextCell * myImageAndTextCelObj;

        

       IBOutlet NSTableView * nsTableViewObj;

    }

   @property (assign) NSMutableArray * nsMutaryOfMyData;

   @property (assign) ImageAndTextCell * myImageAndTextCelObj;

   @property (assign) IBOutlet NSTableView * nsTableViewObj;

    

    //- (IBAction)tableViewSelected:(id)sender;

    

    - (IBAction)addAtSelectedRow:(id)pId;

    - (IBAction)addToEndOfTable:(id)pId;

    - (IBAction)removeCellAtSelectedRow:(id)sender;

    

    

   @end

    

    

    

    

   //

    //  MyController.m

    //  TableViewExample

    

#import "MyController.h"

#import "MyData.h"

#import "ImageAndTextCell.h"

    

    

   @implementation MyController

   @synthesize nsMutaryOfMyData;

   @synthesize nsTableViewObj;

   @synthesize myImageAndTextCelObj;

    //@synthesize nsIntSelectedRow;

    

    // first step

    // cashe the images in MyData

    

    // second step : get the add abd delete going

    

    - (void) awakeFromNib {

        // self.nsIntSelectedRow = -1;

        

       self.nsMutaryOfMyData = [[NSMutableArray alloc]init];

        

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../Lucia.tif"

                                          text:@"Lucia, dog, peacock and Galapagos turtle"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../BellaSeals.tif"

                                          text:@"Bella's Dream (detail): Bella, Lucia and seals"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../BellaPanda.tif"

                                          text:@"Bella's Dream (detail): Bella, Lucia and Panda"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../danceOfLife.tif"

                                          text:@"Stuff That Stars Are Made Of (detail): Dance of Life"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../landBogay.tif"

                                          text:@"View of Bogay"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../landRiverRoeSpring.tif"

                                          text:@"The River Roe in Spring"]];

        [self.nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../oliveHarvest.tif"

                                          text:@"The Olive Harvest"]];

        

        

       self.myImageAndTextCelObj = [[ImageAndTextCell alloc] init];

       self.myImageAndTextCelObj.image =

        [self.nsMutaryOfMyData objectAtIndex:0]nsImageObj];

        [self.myImageAndTextCelObj setEditable:YES];

        NSTableColumn* zTableColumnObj =

        [[self.nsTableViewObj tableColumns] objectAtIndex:0];

        [zTableColumnObj setDataCell:self.myImageAndTextCelObj];

    } // end awakeFromNib

    

    

    // these are called by the table(s)

    

    - (NSInteger)numberOfRowsInTableView:(NSTableView *)pTableView

    {

       return [nsMutaryOfMyData count];

        

    } // end numberOfRowsInTableView

    

    

    - (id)tableView:(NSTableView *)pTableView

objectValueForTableColumn:(NSTableColumn *)pTableColumn

row:(int)pRow {

    

MyData * zMyDataObj= [self.nsMutaryOfMyData objectAtIndex:pRow];

return zMyDataObj.nsStrText;

// Note if returned string is same as that typed into the cell

// then no update takes place

// e.g. returned string="fred", cell = "hello world",

// user selects the word "world" and types "fred": no change takes place.

} // end tableView:objectValueForTableColumn:tableColumn

    

    

    // this is the delegate method that allows you to put data into your cell

    - (void)tableView:(NSTableView *)tableView

willDisplayCell:(id)cell

forTableColumn:(NSTableColumn *)tableColumn

row:(NSInteger)pRow {

//NSLog(@"willDisplayCell");

MyData * zMyDataObj= [self.nsMutaryOfMyData objectAtIndex:pRow];

ImageAndTextCell * zMyCell= (ImageAndTextCell *)cell;

zMyCell.nsImageObj= zMyDataObj.nsImageObj;

[zMyCell setTitle:zMyDataObj.nsStrText];

} // end tableView:willDisplayCell:forTableColumn:row:

    

    

    // this is the routine that returns cell data (an edited string)

    // back after editing

    - (void)tableView:(NSTableView *)aTableView

setObjectValue:anObject

forTableColumn:(NSTableColumn *)aTableColumn

row:(NSInteger)pRow {

MyData * zMyDataObj= [self.nsMutaryOfMyData objectAtIndex:pRow];

NSLog(@"setObjectValue string = %@",(NSString *)anObject);

zMyDataObj.nsStrText= (NSString *)anObject;

} // end tableView:setObjectValue:forTableColumn:row:

    

    

    // if this is not here we crash - called whenever mouseOver

    - (NSCell *)tableView:(NSTableView *)pTableView

dataCellForTableColumn:(NSTableColumn *)pTableColumn

row:(NSInteger)pRow {

//NSLog(@"dataCellForTableColumn");

returnself.myImageAndTextCelObj;

} // end tableView:dataCellForTableColumn:row:

    

    

    //- (IBAction)tableViewSelected:(id)sender {

    //    NSLog(@"the user just clicked on row %d",

    //               [self.nsTableViewObj selectedRow]);

    //} // end tableViewSelected

    

    

    

    - (IBAction)addAtSelectedRow:(id)pId {

        NSLog(@"addAtSelectedRow");

        

        // this ends the editing if an edit was begun

        // just before the addAtSelectedRow button was clicked.

        [[self.nsTableViewObjwindow]makeFirstResponder:[self.nsTableViewObjwindow]];

        

        NSInteger zSelectedRow= [self.nsTableViewObj selectedRow];

       if ( zSelectedRow < 0) {

           return;

        }// end if

        

        NSParameterAssert(zSelectedRow < [self.nsMutaryOfMyData count]);// crash

        

        [nsMutaryOfMyData insertObject:[[MyData alloc]

                                        initWithImagePathString:@"../../../anghiari.tif"

                                        text:@"Copy after Ruben's copy after Leonardo:

                                        The Battle of Anghiari..

                                        And here is some extra text to see how we get on

                                        with very lengthy things"]

                                        atIndex:zSelectedRow];

         

         [self.nsTableViewObj noteNumberOfRowsChanged];

         [self.nsTableViewObj reloadData];

         

         } // end addAtSelectedRow

         

         

         

         - (IBAction)addToEndOfTable:(id)pId {

             NSLog(@"addToEndOfTable");

             [nsMutaryOfMyData addObject:[[MyData alloc]

                                          initWithImagePathString:@"../../../BellaElephants.tif"

                                          text:@"Bella's Dream (detail): Bella and Elephants"]];

             

             [self.nsTableViewObj noteNumberOfRowsChanged];

             [self.nsTableViewObj reloadData];

             

         } // end addToEndOfTable

         

         

         - (IBAction)removeCellAtSelectedRow:(id)sender {

            if ([self.nsTableViewObj selectedRow] <0 || 

                 [self.nsTableViewObj selectedRow] >= [nsMutaryOfMyData count]) {

                return;

             }// end if

             [nsMutaryOfMyData removeObjectAtIndex:[self.nsTableViewObj selectedRow]];

             [self.nsTableViewObj noteNumberOfRowsChanged];

             [self.nsTableViewObj reloadData];

             

         } // end removeCellAtSelectedRow

         

         

         

        @end

         

         

        //

         //  MyData.h

         //  TableViewExample

         

#import 

         

         

        @interface MyData : NSObject {

             NSString * nsStrText;

             NSImage * nsImageObj;

             

         }

        @property (assign) NSString * nsStrText;

        @property (assign) NSImage * nsImageObj;

         

         

         - (id) initWithImagePathString:(NSString *)pImagePath 

                                  text:(NSString *)pText;

         

        @end

         

         

        //

         //  MyData.m

         //  TableViewExample

        //

         

#import "MyData.h"

         

         

        @implementation MyData

        @synthesize nsStrText;

        @synthesize nsImageObj;

         

         - (id) initWithImagePathString:(NSString *)pImagePath 

                                  text:(NSString *)pText {

                                      

                                     if (! (self = [super init])) {

                                          NSLog(@"*Error* MyData initWithImagePathString");

                                         return self;

                                      }// end if

                                      

                                     self.nsStrText = pText;

                                      

                                     self.nsImageObj = [[NSImage alloc] initWithContentsOfFile:pImagePath];

                                      

                                     return self;

                                      

                                  }// end initWithImagePathString

         

        @end



Bindings
Control as NSTableView Data Source and Delegate plus connections to buttons

Control as NSTableView Data Source and Delegate plus connections to buttons

NSTableView Connections: make control the Data Source and Delegate

NSTableView Connections: make control the Data Source and Delegate

Location of image files relative to the xcode source code

Location of image files relative to the xcode source code

Example source code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值