macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Introduction to Cocoa Graphics
Pages: 1, 2, 3

The brush

Our brush in Cocoa is the AppKit class NSBezierPath (also know as bezier path). Like NSView, NSBezierPath is a class jam-packed with all sorts of neat behaviors. Unfortunately, we'll only scratch the surface of today, but we will hit much more of it later on.



Bezier paths are objects that define shapes as a series line and curve segments. For example, a rectangle could be represented as a bezier path with four straight-line segments. With bezier paths, you can make shapes with arbitrary complexity. The procedure for drawing a shape to a view is to first create a path, and then either fill the path with a color, or draw it as an outline. We'll see examples of both shortly.

All drawing code that we write will be done in the method drawRect:. For those of you with experience with Java 2D graphics, drawRect: is analogous to the method paint(). The argument of this method is the rectangle in which the drawing is to be done.

Normally we will never call drawRect: directly. Rather, whenever something changes with our view that requires the contents of the view to be redrawn, that process will tell the view that it needs to be redrawn. Today we won't have any need or reason to manually tell the view to redraw itself, but that will come in a later column.

What we'll work on today is simply how to draw rectangles and ellipses, which are actually almost identical in code. The two methods we will concern ourselves are the convenience constructors +bezierPathWithRect: and +bezierPathWithOvalInRect:. Let's dive right into our first example of drawing and see how it works.

In the drawRect: method, we will add the following code:

- (void)drawRect:(NSRect)rect
{
  NSRect r = NSMakeRect(10, 10, 50, 60);
  NSBezierPath *bp = [NSBezierPath bezierPathWithRect:r];
  NSColor *color = [NSColor blueColor];
  [color set];
  [bp fill];
}

In the first line, we defined the rectangle which would soon become our bezier path. Following that, we created a bezier path object that simply follows the perimeter of the rectangle. In the next line, we created a color that we would fill the rectangle with, and following that, made the current color of subsequent drawing using the -set method of NSColor. The message [color set] tells the graphics engine in the background that any drawing operations will be done with the color blue (as indicated by the object color). Finally, we send a fill message to the bezier path that fills the path with the color we set. This snippet of code should produce the following output:

Screenshot.

Alternatively, we could have made the last line [bp stroke], which would draw a line along the path, as shown below:

Screenshot.

Now, if we changed the bezier path creation line of code (the second line) to the following:

NSBezierPath *bp = [NSBezierPath bexierPathWithOvalInRect:r];

The shape drawn to the screen would be an ellipse that fits into the specified rectangle, as is shown in the image below:

Screenshot.

Another way we can draw a rectangle is using the Foundation function NSRectFill, which takes a rectangle as its argument. The color of the fill operation performed by this function is the current color of the graphics environment. For example, we could change the first example to circumvent the use of NSBezierPath by using the following code:

- (void)drawRect:(NSRect)rect
{
    NSRect r = NSMakeRect(10, 10, 50, 60);
    NSColor *color = [NSColor blueColor];
    [color set];
    NSRectFill(r);
}

NSRectFill is also a convenient way of coloring the background of a view. We can do this by setting a color as the background color, and then passing the drawRect argument variable rect to NSRectFill. Reverting back to our original example, we can make the background black in the following way:

- (void)drawRect:(NSRect)rect
{
    NSRect r;
    NSBezierPath *bp;

    [[NSColor blackColor] set];
    NSRectFill(rect);

    r = NSMakeRect(10, 10, 50, 60);
    bp = [NSBezierPath bezierPathWithRect:r];
    [[NSColor blueColor] set];
    [bp fill];
}

In this example, I eliminated the color variable by sending a set message directly to the object returned by [NSColor blueColor]. This code produces the output shown below.

Screen shot.

This method of coloring the background of the view works because when the method drawRect: is automatically invoked by the view, the boundaries of the view are passed as the rect argument. Another note about the way drawing works -- the background painting code must come before any other drawing commands. This is because objects that are drawn to the view are drawn over anything that was previously there.

End

So that's essentially how you can create shapes using the Cocoa drawing classes! It's pretty simple -- there's not too much to it. In the next column, we will continue with our graphics and drawing discussion by learning how to make more complex paths. Until then, have fun with what you've learned today, experiment, and play around with your ideas. I leave you with a small app that draws a collection of randomly generated rectangles and ellipses to the screen, as is shown in the image below. It's a simple app that doesn't use much else than what we've seen today in terms of drawing code. It can be downloaded here See you next time!

Screenshot.

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.