macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Building a Scratch Pad with Cocoa
Pages: 1, 2

Alternatives

Let's add some more functionality to this little application. We'll set things up so that when we press a key, say c, the view will be cleared of any previous drawing. To do this, we will implement keyDown, as well as reorganize our existing code some. This involves moving the initialization code for path into PadViews init method so that init looks like this:




- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
path = [[NSBezierPath bezierPath] retain];
    }
    return self;
}

In this approach, we are adopting the policy of creating a path object at application launch and never destroying it. Rather than releasing and re-instantiating path, we will remove all points from the path to clear it, as we will see in keyDowns implementation.

MouseDown: looks like the following:


- (void)mouseDown:(NSEvent *)theEvent
{
    NSPoint loc = [theEvent locationInWindow];
    loc.x -= [self frame].origin.x;
    loc.y -= [self frame].origin.y;
    
    [path moveToPoint:loc];
}

Now we want to override NSResponders keyDown method in the following way:


- (void)keyDown:(NSEvent *)theEvent
{
    NSString *keyChar = [theEvent characters];
    if ( [keyChar isEqualToString:@c] ) {
        [path removeAllPoints];
        [self setNeedsDisplay:YES];
    }
}

In a key event, we can use the NSEvent method characters to return a string corresponding to the key pressed. We then compare this to some string that represents the action to be executed, and codify this logic in an if statement. In this case, I choose c -- for clear -- to execute code that clears the path of any elements that it contains.

Learning CocoaLearning Cocoa
By Apple Computer, Inc.
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

But were not done yet. One last thing we have to do is override the NSResponder method acceptsFirstResponder in the following way:


- (BOOL)acceptsFirstResponder
{
    return YES;
}

This method tells anyone who is interested that our NSView subclass will accept being the first responder. If we want keyDown to work here, we need to do this. What exactly does it mean for something to be first responder, and why does it matter here? Lets look into this matter more.

More responder discussion

Also in Programming with Cocoa

Understanding the NSTableView Class

Inside StYNCies, Part 2

Inside StYNCies

Build an eDoc Reader for Your iPod, Part 3

Cocoas event-handling system is based around what is known as a responder chain. As the name suggests, the responder chain is essentially a list of responder objects that are eligible to potentially handle events.

When an event is generated, it is passed to the responder object at the top of the list. If this responder is able to handle the event, then it does, otherwise it passes the buck to the next responder in line on the chain. If this next object can handle the event, then it does. If it cant then the event message continues on up the chain until a responder is found that can handle the event. Generally, the active window is the first responder in the chain, and when a mouse event occurs the window passes the event to the view beneath the mouse cursor, which gives the view the opportunity to respond appropriately, if it can.

With key events, however, the situation is slightly different. Put quite simply, objects that arent at the top of the responder list -- those that arent first responder -- can respond to mouse events as discussed, but cannot respond to key events. To enable an object to respond to key events, we must indicate that it is capable of doing so by returning YES in the overridden acceptsFirstResponder method (by default NO is returned).

This is exactly what we did above to let PadView have the chance to respond to key events. Considering the number of key events that are generated when one types, it makes perfect sense to limit the number of objects that are considered for response to key events.

For a more detailed discussion of the responder chain, check out the class documentation for NSResponder; for a more conceptual discussion of this concept, and why it is used, check out the classic book on object-oriented design, Design Patterns by Gamma et al.; specifically look at the Chain of Responsibility pattern.

At this point you should be able to compile and doodle away! You can download my version of the project here. This little application has lots of potential for simple extensions.

One thing you could do is to add a color well that lets you change the color of the line. If you do this, I anticipate that youll soon want to draw many lines with lots of different colors. Trying to implement this will lead you into the wall that a color applies to an entire bezier path. We cant make different elements different colors. Anyway, have some fun with this and see what you can come up with, and I will see you in the next column!

Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.


Read more Programming With Cocoa columns.

Return to the Mac DevCenter.