Documentation | Manual: Printing
Chapter 10: Printing
In this chapter, we will learn how to print using the Haiku API.
This program for this chapter is called Printing
.ext.
Views
The first thing to understand is that the only thing you can really print in Haiku is a View. However, since it is relatively easy to print text and images to a View, this is not a great limitation.
But it does mean that you have to have a View. Furthermore, that View must be attached to a Window. And since you have a Window, you must also have an Application. In our example, the Application, Window, and View will all be trivial, so we can concentrate on the printing code.
Perl
use Haiku::Window qw(B_TITLED_WINDOW B_QUIT_ON_WINDOW_CLOSE B_ASYNCHRONOUS_CONTROLS B_CURRENT_WORKSPACE); use Haiku::PrintJob qw(:printer_type); my $wframe = Haiku::Rect->new(50, 50, 300, 300); my $title = "Print Window"; my $type = B_TITLED_WINDOW; my $window_flags = B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS; my $workspaces = B_CURRENT_WORKSPACE; my $app = Haiku::Application->new('application/x.vnd-hab.perl.Printing'); my $window = Haiku::Window->new( frame => $wframe, title => $title, type => $type, flags => $window_flags, workspaces => $workspaces, ); my $vframe = Haiku::Rect->new(5,5,105,25); my $name = 'Button'; my $label = "Button!"; my $button = Haiku::Button->new( frame => $vframe, name => "$name 1", label => $label, ); $window->AddChild($button);
Python
wframe = Rect(50, 50, 300, 300) title = "Print Window" type = B_TITLED_WINDOW window_flags = B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS workspaces = B_CURRENT_WORKSPACE app = Application('application/x.vnd-hab.python.Printing') window = Window( frame = wframe, title = title, type = type, flags = window_flags, workspaces = workspaces, ) vframe = Rect(5,5,105,25) name = 'Button' label = "Button!" button = Button( frame = vframe, name = "name 1", label = label, ) window.AddChild(button)
Settings
Every PrintJob has settings, which are set or fetched as a Message. The Message can be Flattened and stored (as an attribute of the file to be printed, for example) and then later read back in and passed to the PrintJob to use the same settings.
The Message holds two sets of settings, each of which is controlled by a
different user dialog. The "Page setup" dialog (called by the ConfigPage
method) controls page layout, and the "Print setup" dialog (called by
ConfigJob
) controls the print session.
As currently designed, however, the page layout is also available from the "Print setup" dialog, so you don't actually need to call ConfigPage at all, unless you need to set the page layout without a print session; for example, to set margins in a WYSIWYG editor.
Perl
# if we had saved seetings from a previous session, we could load them here my $settings; my $job = Haiku::PrintJob->new("job"); if ($job->IsSettingsMessageValid($settings)) { $job->SetSettings($settings) } else { # if the user cancels, ConfigPage will generate an error, so trap it eval { $job->ConfigPage() }; $settings = $job->Settings(); # here we would save off the settings for later reprinting of the same document } # if the user cancels, ConfigJob will generate an error, so trap it eval { $job->ConfigJob() }; $settings = $job->Settings();
Python
# if we had saved seetings from a previous session, we could load them here settings = None job = PrintJob("job") if job.IsSettingsMessageValid(settings): job.SetSettings(settings) else: # if the user cancels, ConfigPage will generate an error, so trap it try: job.ConfigPage() except: pass settings = job.Settings() # here we would save off the settings for later reprinting of the same document # if the user cancels, ConfigJob will generate an error, so trap it try: job.ConfigJob() except: pass settings = job.Settings()
Printing
As a convenience, the first and last page numbers are available from the PrintJOb object, so you don't need to pull them from the settings Message.
The PrintJob will also calculate two rectangles for you, the PaperRect
(representing the size of the paper) and the PrintableRect
(representing the
space within the margins set by the user in the "Page setup" dialog.)
The basic flow of a printing session is:
- BeginJob
- for each page
- check CanContinue
- DrawView
- SpoolPage
- CommitJob
Perl
# if the user chooses to print all pages, LastPage may be something like 2147483647 # so don't assume it's the actual page count my $pagemax = $job->LastPage() - $job->FirstPage() + 1; my $paper_rect = $job->PaperRect(); my $print_rect = $job->PrintableRect(); my $bounds = $print_rect->OffsetToCopy(0,0); $job->BeginJob(); my $pagenum = 0; while ($job->CanContinue() && $pagenum < $pagemax) { $pagenum++; $job->DrawView($button, $bounds, [0,0]); $job->SpoolPage(); last; # just print a single page for this sample # if we were going to print more, we would adjust the bounds to # point to the next section of the View } $job->CommitJob();
Python
# if the user chooses to print all pages, LastPage may be something like 2147483647 # so don't assume it's the actual page count pagemax = job.LastPage() - job.FirstPage() + 1 paper_rect = job.PaperRect() print_rect = job.PrintableRect() bounds = print_rect.OffsetToCopy(0,0) job.BeginJob() pagenum = 0 while job.CanContinue() and pagenum < pagemax: pagenum = pagenum + 1 job.DrawView(button, bounds, [0,0]) job.SpoolPage() break # just print a single page for this sample # if we were going to print more, we would adjust the bounds to # point to the next section of the View job.CommitJob()
And that's basically it. Haiku makes printing easy.
Errors
There is, however, one final caveat:
According the the Be Book, CanContinue
will return false "if the user has
canceled the job, the spool file has grown too big, or something else has
happened to terminate printing". However, as of this writing, CanContinue
will only return false in one of the following conditions:
- you do not call
ConfigJob
- the user cancels the dialog shown by
ConfigJob
- certain errors occur during
BeginJob
- certain errors occur during
CommitJob
- you call
CancelJob
Note that neither DrawView nor SpoolPage will cause CanContinue to return
false; therefore, under Haiku, neither the size of the spool file nor a
problem during drawing will in fact cause the job to terminate. (Although you
could of course, call CancelJob
in your print loop if you make that loop
smart enough to detect such problems.)
This also means that unless you call CancelJob
from your print loop, you
don't actually need to check CanContinue
at the top of the loop, since the
underlying Haiku code will not affect the return value. But it's probably a
good idea to check anyway; that way, if at some point the Haiku code is
changed to update the internal error marker during drawing or spooling, your
code will continue to work with those changes.