In the past, code to handle printing has been difficult to write. Many factors, such as margins, page orientation, and paper size, come into play. The differences in drawing models (between screen drawing and drawing to the printer) have made things even more challenging. Cocoa provides a clean printing interface that uses the same drawing model used to draw to the screen. In addition, just as Cocoa supports the use of calibrated color when drawing to the screen, ColorSync provides advanced color management when printing to paper.
As we saw in Chapter 7, when a view object
receives a drawRect:
message, it responds by
drawing itself into the current graphics context. Usually, this
context is a frame buffer, and the drawRect:
message results in the view drawing its contents to the screen. The
same machinery is used during printing, but the current graphics
context is set to be the printer.
Remember (as discussed in Chapter 7) that the
drawRect:
method is never called directly to make
a view appear on the screen; it is called only when the display
message is sent to the view. The same methodology applies to
printing; the
drawRect:
method is called when a
print:
message is sent to the view. Calling
print:
on a view causes the AppKit to display a
print panel that asks the user which printer she wishes to use (along
with page setup information). When the user clicks the Print button
of the print panel, a sequence of drawRect:
messages—one for each page—is sent to the view.
This chapter focuses on enabling basic printing from Cocoa applications. As with most things, once you have mastered the basics, you can make printing fairly complex—such as adding UI elements to the print panel and using alternate text views to reflow text—to satisfy special needs.
Since Cocoa makes it so easy to print a view, we’re not going to waste any time. The following steps guide you through creating your first print job.
Create a new Cocoa Application project in Project Builder (File → New Project → Application → Cocoa Application) named " View Print”, and save it in your ~/LearningCocoa folder.
Use the Finder to locate the Ripples Blue.jpg file (/Library/Desktop Pictures), and drag it to the Resources group of your project.
Open the MainMenu.nib file in Interface Builder. Click the Images tab on the MainMenu.nib window, and notice that the image we just added is present.
Drag an Image View (NSImageView
) from the Other
Cocoa Views palette onto the main window, and then resize it to be
larger, as shown in Figure 12-1.
Drag the Ripples Blue image from the MainMenu.nib window to the Image View that we just added. When you drop the image onto the view, you should see the image appear there.
Control-drag a connection from the File → Print menu
item to the Image View. The inspector will pop up, if
it’s not already open, and indicate that the menu
item is connected to FirstResponder.print:
.
Disconnect this connection, and connect the File →
Print menu item to the print:
action of the view,
as shown in Figure 12-2. Be careful when dragging
the connection, as it’s easy to select the window as
the target of the action.
Save (
-S) the nib file, and return to Project Builder.
Build and run the project (
-R).
Select Print (File → Print, or
-P) in the running application. The print dialog box will open, as shown in Figure 12-3.
Click the Preview button. The application prints to a PDF file that will be displayed in the Preview application. Repeat the process, and click Print if you want to see the results printed on your printer.
Now that you have printed the view, notice that the entire image view drew itself onto the printer—border and all—and appears just as it did onscreen. If you just wanted to draw the image itself to the printer, you’d need to add a little code to control what gets printed. In the next section, we’ll do just that with text.
Usually,
you’ll want more control over your printing than was
available in our View Print application. This control is provided in
Cocoa by creating print operations (instances of the
NSPrintOperation
class) and running them. You can think of
a print operation as a controller object that mediates between the
underlying print machinery of Mac OS X and the view being printed.
Print operations use a helper object of type
NSPrintInfo
to help them determine how the page
should be printed. If the print operation is constructed without a
print info object, a default print info object for the application
will be used.
We’ll show you how to use print operations and print info objects in conjunction with printing using the document architecture, as covered in Chapter 10 and Chapter 11.
To enable simple printing from a
document-based application simply requires that a
printShowingPrintPanel:
method be implemented
in the document class. This method is called by the document
architecture on the active document when a user selects File
→ Print or presses
-P.
To show this in action, we will create a simple editor that just prints the contents of the text document. So we can just focus on the printing-related code, we’re going to create a new editor rather than using the one we just built. The following steps will guide you:
Create a new Document-Based Application in Project Builder (File → New Project → Application → Cocoa Document-based Application) named “Document Print”, and save it in your ~/LearningCocoa folder.
Design the GUI by opening the MyDocument.nib file in Interface Builder and performing the following steps:
Remove the default text field.
Drag an NSTextView
from the Cocoa Data Views
palette to the application’s window.
Resize the text view so that it occupies the entire window.
Change the Autosizing options so that the view will follow changes in the window’s size.
In Project Builder, open MyDocument.h, and add a declaration as follows for the text view’s outlet:
#import <Cocoa/Cocoa.h>
@interface MyDocument : NSDocument
{
IBOutlet NSTextView * textView;
}
@end
Save (File → Save, or
-S) MyDocument.h; then drag it onto Interface Builder’s MyDocument.nib window so that Interface Builder can pick up the change to the file.
Control-drag a connection from the File’s Owner
object (remember, this is a proxy for the
MyDocument
instance at runtime), and connect it to
the textView
outlet.
Save (File → , or
-S) the nib file.
In Project Builder, open MyDocument.m and add
the printShowingPrintPanel:
method as shown here:
- (void)printShowingPrintPanel:(BOOL)flag { NSPrintInfo * printInfo = [self printInfo]; // a NSPrintOperation * printOp; // b printOp = [NSPrintOperation printOperationWithView:textView // c printInfo:printInfo]; [printOp runOperation]; // d }
The code we added performs the following tasks:
Obtains a reference to the printInfo
object used
by the document. This object is created automatically by
Cocoa’s document architecture for each document.
Declares a printOp
variable of type
NSPrintOperation
.
Creates a new print operation that will print the contents of our text view using the print information that we obtained in line a.
Calls the runOperation
method on the print
operation object. This puts the printing machinery into play.
Save the project (File → Save, or
-S).
Build and run (
-R) the application.
Create some text and then print it (File → Print, or
-P). A print dialog box will appear, as shown in Figure 12-4.
Click either the Print button (to send the print job to your printer) or the Preview button (to send the print information to the Preview application, as shown in Figure 12-5). We recommend that you use the Preview button as you work through this chapter so that a few sheets of paper can be saved.
Use the Page Setup (File → Page Setup, or Shift-
-P) functionality to change the paper size and the orientation used.
When printing text documents, we don’t usually want the text centered on the page; we’d rather have it printed from the top-lefthand corner with some given margin.
Modify our printShowingPanel:
method as follows:
- (void)printShowingPrintPanel:(BOOL)flag { NSPrintInfo * printInfo = [self printInfo]; NSPrintOperation * printOp; [printInfo setTopMargin:36.0]; // a [printInfo setLeftMargin:36.0]; // b [printInfo setHorizontallyCentered:NO]; // c [printInfo setVerticallyCentered:NO]; // d printOp = [NSPrintOperation printOperationWithView:textView printInfo:printInfo]; [printOp runOperation]; }
The code we added performs the following tasks:
Sets the top margin of the printed page to 36 points (1/2 inch). Points are a unit of measure used in page layout and typography, based on a scale of 72 points per inch. See Table 12-1 for a quick reference.
Sets the left margin of the printed page to 36 points.
Indicates that the printed view should not be horizontally centered on the page.
Indicates that the printed view should not be vertically centered on the page.
Save the project (File → Save, or
-S).
Build and run (
-R) the application. Now, when you print out a block of text, it will be printed starting at the upper-left corner, as shown in Figure 12-6.
Complete information on the settings for a print info object can be found in the /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/Printing/index.html file installed on your hard drive with the Developer Tools.
Add a Font menu to the application, and print out files with various fonts.
Add printing to the Dot View application that we created in Chapter 8.
Resize the image view in View Print to occupy the entire window (don’t forget to set the Autosizing attributes!), and experiment with printing other images.