Example code programming Objective-C with Cocoa in Xcode and Interface Builder (Leopard)

41: Animate using NSBitmapImageRep and NSTimer

Problem: We want to create and display a succession of bitmap images and not worry about garbage collection (GC).

Solution: Use Interface Builder to define a NSWindow and a custom NSView. Create an NSBitmapImageRep, set up an NSTimer, change the bitmap values on each iteration,display the NSBitmapImageRep.

Employ a couple of buttons to start and end the animation.

A still from the NSBitmapImageRep animation

A still from the NSBitmapImageRep animation


Create a new project in XCode: File->New Project->Cocoa Application
Call it: 041_NSBitmapImageRep

Now create the class: MyNSView of type NSView.
Code it as shown below and save.

// MyNSView.h // Created by julius on 13/12/2008. #import <Cocoa/Cocoa.h> @interface MyNSView : NSView { NSBitmapImageRep * nsBitmapImageRepObj; NSRect nsRectFrameRect; CGFloat cgFloatRed; CGFloat cgFloatRedUpdate; NSTimer * nsTimerRef; } - (IBAction) startAnimation:(id)pId; - (IBAction) stopAnimation:(id)pId; -(void)paintGradientBitmap; @end // MyNSView.m #import "MyNSView.h" @implementation MyNSView - (id)initWithFrame:(NSRect)pFrameRect { if (! (self = [super initWithFrame:pFrameRect])) { NSLog(@"MyView initWithFrame *Error*"); return self; } // end if nsRectFrameRect = pFrameRect; return self; } - (void)awakeFromNib { nsBitmapImageRepObj = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:nsRectFrameRect.size.width pixelsHigh:nsRectFrameRect.size.height bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:@"NSCalibratedRGBColorSpace" bytesPerRow:0 bitsPerPixel:0]; cgFloatRed = 1.0; cgFloatRedUpdate = 0.02; } // end awakeFromNib - (IBAction) startAnimation:(id)pId { if (nsTimerRef) { [nsTimerRef invalidate]; nsTimerRef = nil; } nsTimerRef = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(paintGradientBitmap) userInfo:NULL repeats:YES]; } // end startAnimation - (IBAction) stopAnimation:(id)pId { [nsTimerRef invalidate]; nsTimerRef = nil; } // end stopAnimation - (void) paintGradientBitmap { // green and blue values are a function of // their position within the nsRectFrameRect. // red has the same value throughout the picture // but changes value with each iteration cgFloatRed += cgFloatRedUpdate; if (cgFloatRed > 1.0) { cgFloatRed = 1.0; cgFloatRedUpdate = cgFloatRedUpdate * (-1.0); cgFloatRed += cgFloatRedUpdate; }; if (cgFloatRed < 0.0) { cgFloatRed = 0.0; cgFloatRedUpdate = cgFloatRedUpdate * (-1.0); cgFloatRed += cgFloatRedUpdate; }; CGFloat zFloatFrameHeight = (CGFloat)nsRectFrameRect.size.height; CGFloat zFloatFrameWidth = (CGFloat)nsRectFrameRect.size.width; NSUInteger zIntRed = round(255.0 * cgFloatRed); NSInteger y; CGFloat zFloatY; for (y = 0; y < nsRectFrameRect.size.height; y++) { zFloatY = (CGFloat)y; NSInteger x; CGFloat zFloatX; NSUInteger zIntBlue = round((255.0 / zFloatFrameHeight) * zFloatY); for (x = 0; x < nsRectFrameRect.size.width; x++) { zFloatX = (CGFloat)x; NSUInteger zIntGreen = round((255.0/zFloatFrameWidth)*zFloatX); NSUInteger zColourAry[3] = {zIntRed,zIntGreen,zIntBlue}; [nsBitmapImageRepObj setPixel:zColourAry atX:x y:y]; } // end for x } // end for y [self setNeedsDisplay:YES]; } // end paintGradientBitmap - (void)drawRect:(NSRect)pRect { [NSGraphicsContext saveGraphicsState]; [nsBitmapImageRepObj drawInRect:pRect]; [NSGraphicsContext restoreGraphicsState]; } // end drawRect @end

Click on the MainMenu.xib to go into Interface Builder. Drag a custom view onto the panel and make it 200 x 200 say.

Add a couple of buttons, name them as shown and connect them to the IBActions in NSView as shown.

In Interface Builder Inspector link the buttons as shown

Link the buttons to the IBActions as shown

Save and Run.

The image starts off as black, click the Start Animation button to see the colours change.

A still from the NSBitmapImageRep animation

A still from the NSBitmapImageRep animation

If you want to download the code

Click the Download Link to obtain 041_NSBitmapImageRep.zip file of this whole OS X 10.5 Leopard program.

Download 041_NSBitmapImageRep.zip (2.2 MB)

Please send me your comments

If you include your e-mail I may reply!  

Page last modified: 18:58 Sunday 12th. May 2013

Julius Guzy

Paintings & Drawings

  • painting after Leonardo Da Vinci's Battle of Anghiari