The chapter “Creating a Custom View” describes the common implementation details for a custom view subclass. This chapter describes advanced view subclassing issues that, although not uncommon, are not required by many view subclasses.
Determining the Output Device
Drawing Outside of drawRect:
Most of a view's displayed image is a stable representation of its state. View objects also interact dynamically with the user, however, and this interaction often involves temporary drawing that isn’t integral to the image itself—selections and other highlighting, for example. Such content should be displayed only to the screen and never to a printer or fax device, or to the pasteboard.
You can determine if a view is drawing to the screen by sending the current graphics context an isDrawingToScreen
message as shown in Listing 5-1.
Listing 5-1 Testing the output device
- (void)drawRect:(NSRect)rect |
{ |
[[NSColor whiteColor] set]; |
NSRectFill(rect); |
// draw a background grid only if we’re drawing to the screen |
if ([[NSGraphicsContext currentContext] isDrawingToScreen]) { |
[self drawGrid]; |
} |
// insert view drawing code here |
} |
If you define methods that need to draw in a view without going through the drawRect:
method, you must send lockFocus
to the target view before any drawing is started and send unlockFocus
as soon as you are done.
It’s perfectly reasonable to lock the focus on one view when another already has it. In fact, this is exactly what happens when subviews are drawn in their superview. The focusing machinery keeps a stack containing the views that have been focused, so that when one view is sent an unlockFocus
message, the focus is restored to the view that was focused immediately before.
Listing 5-2 illustrates using the lockFocus
and unlockFocus
methods to determine the color of the pixel at the cursor location. It would be called from a view's mouseDown:
, mouseUp:
, and mouseMoved:
methods in response to a mouse-down event in a view.
Listing 5-2 Using lockFocus
and unlockFocus
explicitly
- (void) examinePixelColor:(NSEvent *) theEvent |
{ |
NSPoint where; |
NSColor *pixelColor; |
float red, green, blue; |
where = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
// NSReadPixel pulls data out of the current focused graphics context, so -lockFocus is necessary here. |
[self lockFocus]; |
pixelColor = NSReadPixel(where); |
// always balance -lockFocus with an -unlockFocus. |
[self unlockFocus]; |
red = [pixelColor redComponent]; |
green = [pixelColor greenComponent]; |
blue = [pixelColor blueComponent]; |
// we have the color, code that does something with it |
// would reside here |
} |
Note: It is possible for lockFocus
to block if another thread has called lockFocus
on the same view. The queued lockFocus
is executed when the other thread calls unlockFocus
on the view.
© 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-04-10)