Skip to main content

Generating Print Preview of Swing Text Components

Posted by g_s_m on September 5, 2007 at 4:42 AM PDT

This question, “how to generate print preview of Java Swing
components,” is asked often on various discussion forums, because
currently (as of version 6) the Java SE doesn't have standard facilities for
building print previews. While working on the Swing Tutorial, I tried to address this issue under the topic “Using
JTextComponent.getPrintable method.” This will
hopefully appear in the updated version of the Swing Tutorial for JDK6. In the
meantime, I'll put the relevant information here.

There exist several resources on the Internet related to generating print previews in Java, but in most cases they are either commercial, or use an outdated API, or
attempt to build some all-in-one custom dialog solution without paying much
attention to details. In this issue I'll try to focus on how
to create a print preview—what necessary parts are involved and
how they do communicate.

What to Print

The JTextComponent class defines
the getPrintable method which returns an instance of
the Printable interface containing a single
method, print. Assuming the textComponent is
a JTextComponent object we are going to generate print preview for, the
following code shows how to obtain a Printable instance out
of it.

Printable p = textComponent.getPrintable();

Page Format

Next thing we need to know is the parameters of the output media,
most important ones being the physical page dimensions. In real-life
situation the available page dimensions should be obtained by querying
some PrintService known to your Java environment. For
the purposes of this example we'll just use the default page
format.

PageFormat f = new PageFormat();
int pageWidth = f.getWidth();
int pageHeight = f.getHeight();

Where to Print

Then we need a print destination that will receive the actual drawing commands. The destination should be an instance of
the Graphics class. A simple way of obtaining
this is using the BufferedImage class as
physical backing store. This class defines the
getGraphics method which returns a Graphics
instance.

Image page = new BufferedImage(
        pageWidth, pageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics g = page.getGraphics();

How to Print

Now we are ready to generate page images. We need to repeatedly
invoke the print method on the Printable
instance, specifying the page number to print (0 is
the first page) and the
Graphic and PageFormat objects.
The print method returns some status code. The value
of PAGE_EXISTS indicates the success of the operation.

for (int n = 0; p.print(g, f, n) == Printable.PAGE_EXISTS; n++) {
    // N-th page printed successfully
}

How to Scale

The generated page image is usually too large for on-screen
display, so we need to shrink the image for viewing. The following
code creates an image with size reduced by two times on both dimensions.

double scaleFactor = 0.5;
int previewWidth = (int) (pageWidth * scaleFactor);
int previewHeight = (int) (pageHeight * scaleFactor);
Image preview = page.getScaledInstance(
        previewWidth, previewHeight, SCALE_SMOOTH);

Back to Swing

Until now we dealt mostly with 2D and AWT parts of the Client Java API.
Now we need to place the generated preview image into some Swing
component. For this we'll create a subclass of the JPanel,
implementing the custom paintComponent method and
overriding
the getPreferredSize, getMinimumSize
and getMaximumSize methods so our preview component is
laid out correctly.

JPanel previewPane = new JPanel() {
    public void paintComponent(Graphics g) {
        g.drawImage(preview, 0, 0, previewWidth, previewHeight, null);
    }

    public Dimension getPreferredSize() {
        return new Dimension(previewWidth, previewHeight);
    }

    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    public Dimension getMaximumSize() {
        return getPreferredSize();
    }
}

The resulting print preview pane can then be added to Swing
container, just like any other Swing component.

Below are links to the example containing the complete print
preview implementation as described in this issue. Using this
implementation, the print preview functionality could be added to any
text component in a couple lines of code.

Please note that in order to run this demo, you'll need Java runtime version 1.6 (aka 6.0) or higher.

The demo displays a chapter from “Alice in Wonderland” in the
JEditorPane component. Print preview window could be
activated from menu or by using a keyboard shortcut. Standard Java
Print Dialog could be invoked from inside the print preview.

Related Topics >>

Comments

 Hi I am trying to print my swing UI. Its not able to ...

Hi I am trying to print my swing UI. Its not able to take full width of the page. Can you suggest me what can be done about this. Also I saw that there is some bug that width of a jpanel should not be more than height. Is it true? if yes is there any work around?

Generating Print Preview of

Fan Chung-yen said, not pleased, not to have compassion.ugg boots bailey button Chinese society from the Song to 2000, is now fast, I dare not say all of China not as ancient, but at least we have to learn self-cultivation of Fan Tao, ugg boots buyDankan win or lose, live happily, or someday you for ugg boots knitChina which teams they lost to weak teams in Asia and the terminal one of a branch, who would give you the Medal of it?

Want help

Thank you very much for such a nice code. Its really helpful for my college project. But i want some modification on it. Instead of the html file to be display on the preview, can i do it with text control like JTextarea or JLabel? if it is, then how...

You can use JTextArea in

You can use JTextArea in place of JEditorPane because JTextArea, like JEditorPane, is the JTextComponent descendant, and as such provides the getPrintable() method.

However JLabel is *not* a JTextComponent descendant and doesn't provide the getPrintable() method, so you can't print-preview JLabel content using the method described in this article.