Don't use the
BView::Bounds()
function to determine the area to render. Instead, use the update rectangle passed to the
BView::Draw()
function.
A BPrintJob
object runs a printing session. It negotiates everything
after the user's initial request to print—from engaging the Print
Server to calling upon BView
s
to draw and spooling the results to the
printer. It also handles a secondary and somewhat separate matter related
to printing—configuring the page layout.
Users typically don't decide how a document fits on a page—the size of the paper, the width of the margins, the orientation of the image, and so on—each time they print. These decisions are usually made when setting up the document, perhaps from a
menu item, rather than .
To set up the page parameters for a document, an application should
create a BPrintJob
object, assign it a name, and call
ConfigPage()
:
status_tMyDocumentManager
::SetUpPage
() {BPrintJob
job
("document"); returnjob
.ConfigPage
(); }
ConfigPage()
has the Print Server interact with the user to set up the
page configuration. Configuration settings are stored in a
BMessage
object that will be handed to the server when the document is printed.
The BMessage
is important to the server, but the application doesn't need
to look at it directly; functions are provided to access the useful data
it contains. However, you may want to get the object and store it with
the document so that the configuration can be reused whenever the
document is printed—and so that the user's previous choices can be
the default settings when
ConfigPage()
is called again. This is good
behavior for an application to follow, and is highly recommended.
Settings()
returns the page configuration the user set up;
SetSettings()
initializes the configuration that's presented to the user. For example:
BMessage *setup; . . . status_tMyDocumentManager
::SetUpPage
() { status_tresult
;BPrintJob
job
("document's name"); if (setup
) {job
.SetSettings
(newBMessage
(*setup
)); }result
=job
.ConfigPage
(); if (result
==B_OK
) {setup
=job
.Settings
(); /* record the settings for your own use */paper_rect
=job
.PaperRect
();printable_rect
=job
.PrintableRect
(); } returnresult
; }
In this example, the setup
BMessage
presumably is flattened and saved
with the document whenever the document is saved, and unflattened
whenever the document is open and the page settings are needed.
To print a document, an application must go through several ordered steps:
Engaging the Print Server and setting parameters for the job.
Setting up a spool file to hold image data.
Asking BView
s to draw each page.
After each page is drawn, putting the data for the page in the spool file.
Committing the spool file to the Print Server.
A BPrintJob
object has member functions that assist with each step.
A print job begins when the user requests the application to print
something. In response, the application should create a
BPrintJob
object,
assign the job a name, and call
ConfigJob()
to initialize the printing environment. For example:
BMessage *setup
; . . . status_tMyDocumentManager
::BPrintJob
job
("document"); status_terr
; if (setup
)job
.SetSettings
(newBMessage
(*setup
)); if ( (err
=job
.ConfigJob
()) ==B_OK
) { deletesetup
;setup
=job
.Settings
(); } . . . }
So far, this looks much like the code for configuring the page presented
in the previous
"Setting Up the Page Layout"
section. The idea is the same.
ConfigJob()
gets the Print Server ready for a new printing session
and has it interact with the user to set up the parameters for the
job—which pages, how many copies, and so on. It uses the same settings
BMessage
to record the user's choices as
ConfigPage()
did,
though it records information that's more immediate to the particular
printing session.
Again, you may want to store the user's choices with the document so that
they can be used to set the initial configuration for the job when the
document is next printed. By calling
Settings()
,
you can get the job configuration the user set up;
SetSettings()
initializes the configuration that's presented to the user.
Information about the page layout will be required while printing. If
that information isn't available in the
Settings()
BMessage
,
ConfigJob()
will begin, in essence, by calling
ConfigPage()
so that the server can ask the user to supply it.
To discover which pages the user wants to print, you can call the
FirstPage()
and
LastPage()
functions after
ConfigJob()
returns:
int32pageCount
=job
.LastPage
() -job
.FirstPage
() + 1;
The next step after configuring the job is to call
BeginJob()
to set up a spool file and begin the production of pages. After all the pages are
produced,
CommitJob()
is called to commit them to the printer.
job
.BeginJob
(); /* draw pages here*/job
.CommitJob
();
BeginJob()
and
CommitJob()
bracket all the drawing that's done during the job.
A number of things can happen to derail a print job after it has
started—most significantly, the user can cancel it at any time. To
be sure that the job hasn't been canceled or something else hasn't
happened to defeat it, you can call
CanContinue()
at critical junctures in your code. This function will tell you whether it's sensible to
continue with the job. In the following example, a while loop is used to
loop through all the pages in the document, or until
CanContinue()
returns false, indicating that the job has been canceled:
job
.BeginJob
(); while (job
.CanContinue
() &&page
<=pageCount
) { /* draw each page here*/page
++; }job
.CommitJob
();
A page is produced by asking one or more
BView
s
to draw within a rectangle that can be mapped to a sheet of paper (excluding the margins
at the edge of the paper).
DrawView()
requests one BView
to draw some
portion of its data and specifies where the data should appear on the
page. You can call
DrawView()
any number of times for a single page to
ask any number of BView
s
to contribute to the page. After all views have drawn,
SpoolPage()
spools the data to the file that will eventually be committed to the printer.
SpoolPage()
is called just once for each page. For example:
for (inti
=job
.FirstPage
();job
.CanContinue
() &&i
<=job
.LastPage
();i
++) { . . .job
.DrawView
(someView
,viewRect
,pointOnPage
);job
.DrawView
(anotherView
,anotherRect
,differentPoint
); . . .job
.SpoolPage
(); }
DrawView()
calls the BView
's
Draw()
function. That function must be
prepared to draw either for the screen or on the printed page. It can
test the destination of its output by calling the
Draw()
IsPrinting()
function.
Don't use the
BView::Bounds()
function to determine the area to render. Instead, use the update rectangle passed to the
BView::Draw()
function.
This function puts together all the above code snippets and handles the printing of a document (minus the actual drawing and visual status information presented to the user as printing goes on).
status_tMyDocumentManager
::result
=B_OK
;BPrintJob
job
("document's name"); // If we have no setup message, we should call ConfigPage() // You must use the same instance of the BPrintJob object // (you can't call the previous "PageSetup()" function, since it // creates its own BPrintJob object). if (!setup
) {result
=job
.ConfigPage
(); if (result
==B_OK
) { // Get the user Settingssetup
=job
.Settings
(); // Use the new settings for your internal usepaper_rect
=job
.PaperRect
();printable_rect
=job
.PrintableRect
(); } } if (result
==B_OK
) { // Setup the driver with user settingsjob
.SetSettings
(setup
);result
=job
.ConfigJob
(); if (result
==B_OK
) { // WARNING: here, setup CANNOT be NULL. if (setup
==NULL
) { // something's wrong, handle the error and bail out } deletesetup
; // Get the user Settingssetup
=job
.Settings
(); // Use the new settings for your internal use // They may have changed since the last time you read itpaper_rect
=job
.PaperRect
();printable_rect
=job
.PrintableRect
(); // Now you have to calculate the number of pages // (note: page are zero-based) int32firstPage
=job
.FirstPage
(); int32lastPage
=job
.LastPage
(); // Verify the range is correct // 0 ... LONG_MAX -> Print all the document // n ... LONG_MAX -> Print from page n to the end // n ... m -> Print from page n to page m if (lastPage
>your_document_last_page
)last_page
=your_document_last_page
; int32nbPages
=lastPage
-firstPage
+ 1; // Verify the range is correct if (nbPages
<= 0) returnB_ERROR
; // Now you can print the pagejob
.BeginJob
(); // Print all pages boolcan_continue
=job
.CanContinue
(); for (inti
=firstPage
;can_continue
&&i
<=lastPage
;i
++) { // Draw all the needed viewsjob
.DrawView
(someView
,viewRect
,pointOnPage
);job
.DrawView
(anotherView
,anotherRect
,differentPoint
); // If the document have a lot of pages, you can update a BStatusBar, here // or else what you want...update_status_bar
(i
-firstPage
,nbPages
); // Spool the pagejob
.SpoolPage
(); // Cancel the job if needed. // You can for exemple verify if the user pressed the // ESC key or (SHIFT + '.')... if (user_has_canceled
) { // tell the print_server to cancel the printjobjob
.CancelJob
();can_continue
=false
; break; } // Verify that there was no error (disk full for example)can_continue
=job
.CanContinue
(); } // Now, you just have to commit the job! if (can_continue
)job
.CommitJob
(); elseresult
=B_ERROR
; } } returnresult
; }
When a BView
draws for the printer, it draws within the printable
rectangle of a page—a rectangle that matches the size of a sheet of
paper minus the unprinted margin around the paper's edge. The
PaperRect()
function returns a rectangle that measures a sheet of paper and
PrintableRect()
returns the printable rectangle, as illustrated in this
diagram.
Both rectangles are stated in a coordinate system that has its origin at
the left top corner of the page. Thus, the left and top sides of the
rectangle returned by
PaperRect()
are always 0.0.
PrintableRect()
locates
the printable rectangle on the paper rectangle. However,
DrawView()
assumes coordinates that are local to the printable rectangle—that
is, an origin at the left top corner of the printable rectangle rather
than the paper rectangle.
The diagram below shows the left top coordinates of the printable rectangle as
PrintableRect()
would report them and as
DrawView()
would assume them, given a half-inch margin.
Draw()
always draws in the
BView
's
own coordinate system. Those
coordinates are mapped to locations in the printable rectangle as
specified by the arguments passed to
DrawView()
.
See also:
BView::IsPrinting()