You create NSPrintOperation objects in response to the user choosing the Print menu command. You initialize the print operation object with the view to be printed and, optionally, the NSPrintInfo object holding the print settings. The operation is not started, however, until you invoke one of NSPrintOperation’s runOperation
methods. For example, a view can have a simple print:
method as in the following example, which merely starts a print operation for the view that receives the print:
message:
- (void)print:(id)sender { |
[[NSPrintOperation printOperationWithView:self] runOperation]; |
} |
This implementation of print:
starts by creating an NSPrintOperation object, which manages the process of generating proper code for a printer device. When run, the NSPrintOperation object creates and displays a modal print panel, an NSPrintPanel object, to obtain the print settings from the user. The application’s shared NSPrintInfo object is used for the initial settings. The method blocks until the print operation is complete.
This NSView-based implementation works best when you have only one printable view in your window that can ever be the first responder. For example, in a simple text editor, only the view holding the text document can have the focus, so it is safe to implement printing in the text view. You can see an example of this architecture in the TextEdit example project.
When your user interface contains multiple views that can have focus, such as multiple NSTextFields, this implementation breaks down. When you choose the Print menu command, the view that receives the print:
message prints itself, but nothing else. If the focus is in an NSTextField, for example, only the contents of that text field is printed. This probably is not the desired behavior. Instead, your application needs to take a more document-based approach.
In a document-based model, you need to customize the Print menu command (as usually defined in the main nib file) to send a different message that one of your objects higher in the responder chain, such as a window or application delegate, implements. Your class can then identify, or perhaps construct, the view that you want printed, regardless of which particular view in the window has the current focus. You can also assign separate NSPrintInfo objects to each open document or window.
NSDocument-based applications, such as the Sketch example project, behave as just described. If you create an NSDocument-based application in Xcode, the Print menu command in the default main nib file sends a printDocument:
message instead of print:
. If you provide your own document architecture, you must edit the nib file yourself.
Assuming the Print menu command now sends a printDocument:
message, your document-based application can run a print operation as follows:
- (void)printDocument:(id)sender { |
// Assume documentView returns the custom view to be printed |
NSPrintOperation *op = [NSPrintOperation |
printOperationWithView:[self documentView] |
printInfo:[self printInfo]]; |
[op runOperationModalForWindow:[self documentWindow] |
delegate:self |
didRunSelector: |
@selector(printOperationDidRun:success:contextInfo:) |
contextInfo:NULL]; |
} |
- (void)printOperationDidRun:(NSPrintOperation *)printOperation |
success:(BOOL)success |
contextInfo:(void *)info { |
if (success) { |
// Can save updated NSPrintInfo, but only if you have |
// a specific reason for doing so |
// [self setPrintInfo: [printOperation printInfo]]; |
} |
} |
printDocument:
now creates an NSPrintOperation with the document’s NSPrintInfo object—not the application’s shared NSPrintInfo object. It also uses the runOperationModalForWindow:delegate:didRunSelector:contextInfo:
method to run the NSPrintPanel as a sheet on the document’s window. This way, the application is not blocked and can continue processing events. The print operation delegate object, self
in this case, is sent a message when the print operation completes. The callback method can check whether the operation was successful and perform additional actions if necessary. For example, on success the method can save the print operation’s NSPrintInfo object for use by the next print operation. It is recommended that most applications not save the print info object between print operations. This ensures that the Print panel displays with the appropriate default settings each time.
There are a number of ways you can customize the behavior of a print operation. These include running a print operation without a print panel and customizing the print panel.
By default, an NSPrintOperation object displays an NSPrintPanel object allowing the user to select printing options, such as number of copies to print and range of pages to print. After the user fills this out the first time, you may want to offer the user the ability to by-pass the Print panel and just print immediately using the previous print settings.
You can suppress the display of the NSPrintPanel object by sending setShowPanels:
with a NO
argument to the NSPrintOperation object before running the operation. However, make sure that any non-default settings in the NSPrintInfo object that would normally be selected from an NSPrintPanel object are set to reasonable values—a copy of an NSPrintInfo object used in a previous print job will have the correct values. This is illustrated in the following example:
// Invoked in response to the standard "Print..." menu command |
- (void)print:(id)sender { |
NSPrintOperation *op = [NSPrintOperation printOperationWithView:self |
printInfo:[self printInfo]]; |
if ( [op runOperation] ) |
[self setPrintInfo:[op printInfo]]; |
} |
// Invoked in response to a custom "Print Now" menu command |
- (void)printWithNoPanel:(id)sender { |
NSPrintOperation *op; |
op = [NSPrintOperation printOperationWithView:self |
printInfo:[self printInfo]]; |
[op setShowPanels:NO]; |
[op runOperation]; |
} |
By default, an NSPrintOperation displays a standard NSPrintPanel. If you need to add some application-specific options, you can add an accessory view. You can load the accessory view from a nib file or create it programmatically. After creating the NSPrintOperation, send it your view with the setAccessoryView:
method:
- (void)print:(id)sender { |
NSPrintOperation *op; |
op = [NSPrintOperation printOperationWithView:self]; |
// Assume printAccessoryView loads or creates your custom view |
[op setAccessoryView:[self printAccessoryView]]; |
[op runOperation]; |
} |
If you need to make more extensive changes to the Print panel, you can subclass NSPrintPanel. You tell NSPrintOperation to use your custom subclass instead of the default panel using its setPrintPanel:
method.
- (void)print:(id)sender { |
NSPrintOperation *op; |
MyPrintPanel *myPanel = [[MyPrintPanel alloc] init]; |
op = [NSPrintOperation printOperationWithView:self]; |
[op setPrintPanel:myPanel]; |
[op runOperation]; |
[myPanel release]; |
} |
A print operation does not have to send its results to a printer. You can have the operation generate raw PDF or EPS data and write the data either to an NSMutableData object you provide or to a file at a path you specify. To do so, use one of the EPSOperation
or PDFOperation
class methods to create the NSPrintOperation instead of one of the printOperation
methods. You can identify whether a print operation is generating PDF or EPS data by sending it an isCopyingOperation
message, which returns YES
in this case; it returns NO
if the data are being sent to a printer.
NSView provides several convenience methods for generating PDF and EPS data. The data can be returned in an NSData or written to a pasteboard. For PDF data, NSView implements dataWithPDFInsideRect:
and writePDFInsideRect:toPasteboard:
. For EPS the methods are dataWithEPSInsideRect:
and writeEPSInsideRect:toPasteboard:
.
These methods create and run an NSPrintOperation, like print:
does, but the print panel is not displayed. They still use the shared NSPrintInfo object if one is provided, but do not allow the user to modify the defaults.
Last updated: 2006-06-28