To provide a completely custom pagination scheme that does not use NSView’s built-in pagination support, a view must override the knowsPageRange:
method to return YES
. It should also return by reference the page range for the document. Before printing each page, the pagination machinery sends the view a rectForPage:
message. Your implementation of rectForPage:
should use the supplied page number and the current printing information to calculate an appropriate drawing rectangle in the view’s coordinate system.
The following example shows a very simple implementation that merely splits the view vertically into the maximum page-sized pieces:
// Return the number of pages available for printing |
- (BOOL)knowsPageRange:(NSRangePointer)range { |
NSRect bounds = [self bounds]; |
float printHeight = [self calculatePrintHeight]; |
range->location = 1; |
range->length = NSHeight(bounds) / printHeight + 1; |
return YES; |
} |
// Return the drawing rectangle for a particular page number |
- (NSRect)rectForPage:(int)page { |
NSRect bounds = [self bounds]; |
float pageHeight = [self calculatePrintHeight]; |
return NSMakeRect( NSMinX(bounds), NSMaxY(bounds) - page * pageHeight, |
NSWidth(bounds), pageHeight ); |
} |
// Calculate the vertical size of the view that fits on a single page |
- (float)calculatePrintHeight { |
// Obtain the print info object for the current operation |
NSPrintInfo *pi = [[NSPrintOperation currentOperation] printInfo]; |
// Calculate the page height in points |
NSSize paperSize = [pi paperSize]; |
float pageHeight = paperSize.height - [pi topMargin] - [pi bottomMargin]; |
// Convert height to the scaled view |
float scale = [[[pi dictionary] objectForKey:NSPrintScalingFactor] |
floatValue]; |
return pageHeight / scale; |
} |
As part of the custom pagination, you can also add extra features to the page, such as crop marks, date/time strings, or page numbers. This is done, for each page, with drawPageBorderWithSize:
.
You must override drawPageBorderWithSize:
to make it functional, as its default implementation prints nothing to the page. In this method, first save the view’s existing body frame—it will need to be restored at the end of the method. Once the old frame is saved, resize the body frame to a rect with origin (0,
0)
and a size equal to the incoming borderSize parameter. This new frame now encompasses the margins instead of hiding them.
Once the frame is expanded, you can add your custom border elements to all four margin areas (top, bottom, left, and right). Drawing is typically done with drawAtPoint:
. Any set of drawing calls must be preceded by lockFocus:
and followed by unlockFocus:
, otherwise drawPageBorderWithSize:
will not draw anything to the page for those calls. Use the paper and margin dimensions from the print info object to constrain the printable area and prevent drawPageBorderWithSize:
from printing within the body text frame. If you wish to print within the body text frame—to print a watermark, for example—do so by printing directly in the newly enlarged frame and ignoring the margin constraints.
Reset the frame to the body text area before exiting the method; this assures the next page of content will print only within the paginated portion of the view.
Last updated: 2006-06-28