JavaPrinting from Java

Printing from Java

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.



The introduction of Java 1.1 has enabled Java developers to incorporate printing quickly and easily into their work without having to rely on awkward and non-portable third-party packages. Printing from a Java application is simple; printing from an applet, though slightly more complex, is still fairly straightforward. Even as late as JDK 1.1.5, however, platform-specific bugs abound.

The concept

If you have done any printing on other platforms, it shouldn’t surprise you that all you need to do in Java to print is to draw into a graphics context for the printer. Whatever you draw will get printed. The trick then is to get a graphics context for the printer. You do that through the Toolkit method,

getPrintJob()
.

getPrintJob()
returns a reference to a PrintJob object after displaying a dialog box allowing the user to configure the print job — for instance, whether to print in portrait or landscape mode, the number of copies to print, etc. With the PrintJob object in hand, you simply call its

getGraphics()
method to get a graphics context and proceed to draw into it. When you are done, you should dispose of the graphics context and clean up with

end()
.

The code looks like this:


public void doPrint () {<BR>
<UL>
PrintJob pj = getToolkit().getPrintJob (null, “My Print Job”, null);<BR>
if (pj != null) {<BR>
<UL>
Graphics pg = pj.getGraphics();<BR>
pg.drawRect (100,100,200,200);<P>

// the page is sent to the printer when the graphics object<BR>
// is disposed.<BR>
pg.dispose();<BR>
pj.end();<BR>
</UL>
}<BR>
// else the user canceled out of the print options dialog<BR>
</UL>
}

getPrintJob()
takes three parameters. The first is a Frame object, the second is the title for the print job and the third is a Properties reference. Typically, the frame reference you pass in would be the frame you are printing. However, if your program is an applet, you don’t readily have a frame printing, so you can pass in null for this parameter. The second parameter is the title of the print job. If your printer generates cover sheets, for instance, the title would appear on the cover sheet. Unfortunately, here we get into some of the platform differences and bugs mentioned earlier. On Win32, it doesn’t matter what you name your print job. It will always be called AWT Print. On Solaris, the print job is named properly. (See bug #4100004) The last parameter to

getPrintJob()
is a properties object. You can set the properties prior to calling

getPrintJob
(in which case the properties will be set as the default choices in the print options dialog), as well as get the properties to check what the user set in the print options dialog. The list of properties relevant to printing are:
  • awt.print.destination – can be “printer” or “file”
  • awt.print.printer – print command
  • awt.print.fileName – name of the file to print
  • awt.print.numCopies – the number of copies to print
  • awt.print.options – options to pass to the print command
  • awt.print.orientation – can be “portrait” or “landscape”
  • awt.print.paperSize – can be “letter,” “legal,” “executive” or “a4”

These print properties, however, are only relevant for Solaris and are consequently useless for other platforms. According to JavaSoft, this is not a bug. The print dialog is platform-dependent and cannot be expected to be part of Java’s platform-independent architecture. Essentially, it would violate the Java specification to communicate with platform-dependent dialogs. (This also means that it is unlikely that Java will provide you with a means to print without displaying the print dialog.) In the case of Solaris, however, there is no print dialog and so JavaSoft “hacked up” one in Java, using the properties parameter to pass values back and forth. (See bug #4036938). So, basically, it is fine to pass in null for the properties parameter.

The practice

Once you have a print job and the print job’s graphics context, it is simply a matter of formatting your print job and then rendering it. Components (like frames and applets) provide you with two methods,

print()
and

printAll()
to help you print.

 is intended to be overridden.  The default implementation simply calls the component’s paint() method.

<P>By overriding <CODE>print()

, you can layout your print job differently from how it might appear on screen.

printAll()
prints the component and all of its subcomponents. The PrintJob object has a few methods that give you information about the page layout. These methods are getPageDimension(), getPageResolution(), and lastPageFirst().Given the information returned by these methods, you can format your print job to fit the given dimensions. For instance: public void print (Graphics g) {


<UL>
// cast the Graphics object to PrintGraphics in order to get the PrintJob<BR>
PrintJob pj = ((PrintGraphics)g).getPrintJob();<BR>
Dimension d = pj.getPageDimension();<P>

// continue to layout page based on page dimensions<BR>
g.setFont (new Font(“Helvetica”, Font.PLAIN, 10));<BR>
g.drawString (“Hello World”, 100, 100);<BR>
</UL>
}

Don’t be surprised however, if when you try to do some simple things, you encounter problems. For instance, it is a known bug that if you use

drawString()
without first setting the font, you will get a null pointer exception (see bug #4080817). If other problems occur, it might be a good idea to see if they are known bugs or not. A good resource is the Java Developer Connection’s bug parade.

Applets versus applications

Printing from applets is really no different than printing from applications. The catch, however, is that printing is “outside the sandbox;” that is, the applet security manager will raise a security exception when your applet calls

getPrintJob()
.

So how do you print from an applet? You can do so only by using Netscape Communicator, a signed applet, and Netscape’s Capabilities classes (see “Introduction to the Capabilities Classes“).

Without going into too much detail, Netscape Communicator enables signed applets to request permission to access various system resources. It is left up to the user to grant or deny access.

An applet requests access to a system’s printing resources by enabling the

UniversalPrintJobAccess
privilege. Once the privilege has been granted, the applet can proceed exactly as outlined above. To enable the print job privilege, you use the following code:


import netscape.security.PrivilegeManager;<BR>
import netscape.security.ForbiddenTargetException;<BR>
.<BR>
.<BR>
try {<BR>
<UL>
PrivilegeManager.enablePrivilege (“UniversalPrintJobAccess”);<BR>
// proceed with printing as normal<P>

PrivilegeManager.disablePrivilege (“UniversalPrintJobAccess”);<BR>
</UL>
} catch (ForbiddenTargetException e) {<BR>
<UL>
// user denied applet permission to access resource<BR>
</UL>
}

Conclusion

The process of adding printing to your Java applications and applets is fairly similar to that used on other platforms where you render into a graphics context for the printer. For more information, once you’ve mastered the information provided in this overview, you may want to look into Netscape Capabilities classes and signed applets.

As you now begin to incorporate printing in your applications and applets, just remember to recycle. You can go through a lot of paper as you fine tune your application’s printing abilities.

Dan Gildor is a consultant for inTouch Technology Corp. specializing in cross-platform intranet and extranet technologies. He can be reached at gyld@in-touch.com.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories