Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Swing Chapter 22. (Special topics) Printing. Easy for reading, Click here!

Custom Search
Swing Chapter 22. (Special topics) Printing. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 3/5 



Previous Page Previous Page (2/5) - Next Page (4/5) Next Page
Subpages: 1. Java 2 Printing API overview
2. Printing images
3. Print preview
4. Printing styled text
5. Printing tables

22.3  Print preview

Print preview functionality has became a standard service provided by most modern print-enabled applications. It only makes sense to include this service in Java 2 applications. The example in this section shows how to construct a print preview component.

Note: An additional reason for Java developers to add print preview to their programs is that this service can be very useful for debugging print code. Slow performance of the Java printing API can make debugging impractical using an actual printer.

The print preview component displays small images of the printed pages as they would appear after printing. A GUI attached to the preview component typically allows for changing the scale of the preview images and invoking a print. The following example demonstrates such a component which can be easily added to any print-aware Swing application.

Figure 22.4 Print preview showing a 1200x1500 image split into 9 parts.

<<figure22-4.gif>>

The Code: JPEGEditor.java

see \Chapter22\2

public class JPEGEditor extends JFrame

{

  // Unchanged code from section 22.2

  protected JMenuBar createMenuBar() {

    // Unchanged code from section 22.2

    mItem = new JMenuItem("Print Preview");

    mItem.setMnemonic('v');

    ActionListener lstPreview = new ActionListener() {

      public void actionPerformed(ActionEvent e) {

        Thread runner = new Thread() {

          public void run() {

            setCursor(Cursor.getPredefinedCursor(

              Cursor.WAIT_CURSOR));

            if (m_panel.getBufferedImage() != null)

              new PrintPreview(m_panel,

               m_currentFile.getName()+" preview");

            setCursor(Cursor.getPredefinedCursor(

              Cursor.DEFAULT_CURSOR));

          }

        };

        runner.start();

      }

    };

    mItem.addActionListener(lstPreview);

    mFile.add(mItem);

    mFile.addSeparator();

// The rest of the code is unchanged from section 22.2

The Code: PrintPreview.java

see \Chapter22\2

import java.awt.*;

import java.awt.event.*;

import java.awt.image.*;

import java.util.*;

import java.awt.print.*;

import javax.swing.*;

import javax.swing.border.*;

import javax.swing.event.*;

public class PrintPreview extends JFrame

{

  protected int m_wPage;

  protected int m_hPage;

  protected Printable m_target;

  protected JComboBox m_cbScale;

  protected PreviewContainer m_preview;

  public PrintPreview(Printable target) {

    this(target, "Print Preview");

  }

  public PrintPreview(Printable target, String title) {

    super(title);

    setSize(600, 400);

    m_target = target;

    JToolBar tb = new JToolBar();

    JButton bt = new JButton("Print", new ImageIcon("print.gif"));

    ActionListener lst = new ActionListener() {

      public void actionPerformed(ActionEvent e) {

        try {

          // Use default printer, no dialog

          PrinterJob prnJob = PrinterJob.getPrinterJob();

          prnJob.setPrintable(m_target);

          setCursor( Cursor.getPredefinedCursor(

            Cursor.WAIT_CURSOR));

          prnJob.print();

          setCursor( Cursor.getPredefinedCursor(

            Cursor.DEFAULT_CURSOR));

          dispose();

        }

        catch (PrinterException ex) {

          ex.printStackTrace();

          System.err.println("Printing error: "+ex.toString());

        }

      }

    };

    bt.addActionListener(lst);

    bt.setAlignmentY(0.5f);

    bt.setMargin(new Insets(4,6,4,6));

    tb.add(bt);

    bt = new JButton("Close");

    lst = new ActionListener() {

      public void actionPerformed(ActionEvent e) {

        dispose();

      }

    };

    bt.addActionListener(lst);

    bt.setAlignmentY(0.5f);

    bt.setMargin(new Insets(2,6,2,6));

    tb.add(bt);

    String[] scales = { "10 %", "25 %", "50 %", "100 %" };

    m_cbScale = new JComboBox(scales);

    lst = new ActionListener() {

      public void actionPerformed(ActionEvent e) {

        Thread runner = new Thread() {

          public void run() {

            String str = m_cbScale.getSelectedItem().

              toString();

            if (str.endsWith("%"))

              str = str.substring(0, str.length()-1);

            str = str.trim();

              int scale = 0;

            try { scale = Integer.parseInt(str); }

            catch (NumberFormatException ex) { return; }

            int w = (int)(m_wPage*scale/100);

            int h = (int)(m_hPage*scale/100);

            Component[] comps = m_preview.getComponents();

            for (int k=0; k<comps.length; k++) {

              if (!(comps[k] instanceof PagePreview))

                continue;

              PagePreview pp = (PagePreview)comps[k];

                pp.setScaledSize(w, h);

            }

            m_preview.doLayout();

            m_preview.getParent().getParent().validate();

          }

        };

        runner.start();

      }

    };

    m_cbScale.addActionListener(lst);

    m_cbScale.setMaximumSize(m_cbScale.getPreferredSize());

    m_cbScale.setEditable(true);

    tb.addSeparator();

    tb.add(m_cbScale);

    getContentPane().add(tb, BorderLayout.NORTH);

    m_preview = new PreviewContainer();

    PrinterJob prnJob = PrinterJob.getPrinterJob();

    PageFormat pageFormat = prnJob.defaultPage();

    if (pageFormat.getHeight()==0 || pageFormat.getWidth()==0) {

      System.err.println("Unable to determine default page size");

        return;

    }

    m_wPage = (int)(pageFormat.getWidth());

    m_hPage = (int)(pageFormat.getHeight());

    int scale = 10;

    int w = (int)(m_wPage*scale/100);

    int h = (int)(m_hPage*scale/100);

    int pageIndex = 0;

    try {

      while (true) {

        BufferedImage img = new BufferedImage(m_wPage,

          m_hPage, BufferedImage.TYPE_INT_RGB);

        Graphics g = img.getGraphics();

        g.setColor(Color.white);

        g.fillRect(0, 0, m_wPage, m_hPage);

        if (target.print(g, pageFormat, pageIndex) !=

         Printable.PAGE_EXISTS)

          break;

        PagePreview pp = new PagePreview(w, h, img);

        m_preview.add(pp);

        pageIndex++;

      }

    }

    catch (PrinterException e) {

      e.printStackTrace();

      System.err.println("Printing error: "+e.toString());

    }

    JScrollPane ps = new JScrollPane(m_preview);

    getContentPane().add(ps, BorderLayout.CENTER);

    setDefaultCloseOperation(DISPOSE_ON_CLOSE);

    setVisible(true);

  }

  class PreviewContainer extends JPanel

  {

    protected int H_GAP = 16;

    protected int V_GAP = 10;

    public Dimension getPreferredSize() {

      int n = getComponentCount();

      if (n == 0)

        return new Dimension(H_GAP, V_GAP);

      Component comp = getComponent(0);

      Dimension dc = comp.getPreferredSize();

      int w = dc.width;

      int h = dc.height;

      Dimension dp = getParent().getSize();

      int nCol = Math.max((dp.width-H_GAP)/(w+H_GAP), 1);

      int nRow = n/nCol;

      if (nRow*nCol < n)

        nRow++;

      int ww = nCol*(w+H_GAP) + H_GAP;

      int hh = nRow*(h+V_GAP) + V_GAP;

      Insets ins = getInsets();

      return new Dimension(ww+ins.left+ins.right,

        hh+ins.top+ins.bottom);

    }

    public Dimension getMaximumSize() {

      return getPreferredSize();

    }

    public Dimension getMinimumSize() {

      return getPreferredSize();

    }

    public void doLayout() {

      Insets ins = getInsets();

      int x = ins.left + H_GAP;

      int y = ins.top + V_GAP;

      int n = getComponentCount();

      if (n == 0)

        return;

      Component comp = getComponent(0);

      Dimension dc = comp.getPreferredSize();

      int w = dc.width;

      int h = dc.height;

      Dimension dp = getParent().getSize();

      int nCol = Math.max((dp.width-H_GAP)/(w+H_GAP), 1);

      int nRow = n/nCol;

      if (nRow*nCol < n)

        nRow++;

      int index = 0;

      for (int k = 0; k<nRow; k++) {

        for (int m = 0; m<nCol; m++) {

          if (index >= n)

            return;

          comp = getComponent(index++);

          comp.setBounds(x, y, w, h);

          x += w+H_GAP;

        }

        y += h+V_GAP;

        x = ins.left + H_GAP;

      }

    }

  }

  class PagePreview extends JPanel

  {

    protected int m_w;

    protected int m_h;

    protected Image m_source;

    protected Image m_img;

    public PagePreview(int w, int h, Image source) {

      m_w = w;

      m_h = h;

      m_source= source;

      m_img = m_source.getScaledInstance(m_w, m_h,

        Image.SCALE_SMOOTH);

      m_img.flush();

      setBackground(Color.white);

      setBorder(new MatteBorder(1, 1, 2, 2, Color.black));

    }

    public void setScaledSize(int w, int h) {

      m_w = w;

      m_h = h;

      m_img = m_source.getScaledInstance(m_w, m_h,

        Image.SCALE_SMOOTH);

      repaint();

    }

    public Dimension getPreferredSize() {

      Insets ins = getInsets();

      return new Dimension(m_w+ins.left+ins.right,

        m_h+ins.top+ins.bottom);

    }

    public Dimension getMaximumSize() {

      return getPreferredSize();

    }

    public Dimension getMinimumSize() {

      return getPreferredSize();

    }

    public void paint(Graphics g) {

      g.setColor(getBackground());

      g.fillRect(0, 0, getWidth(), getHeight());

      g.drawImage(m_img, 0, 0, this);

      paintBorder(g);

    }

  }

}

Understanding the Code

Class JPEGEditor

Compared to the previous example this class has only one difference: it creates a menu item titled "Print Preview." When selected, this item creates an instance of the PrintPreview class (see below). This class's constructor takes two parameters: a reference to a Printable instance and a text string for the frame's title. As we have seen in the previous example, our m_panel component implements the Printable interface and provides the actual printing functionality, so we use it to create the PrintPreview instance. Note that this call is wrapped in a thread because, when used with large images, creation of a PrintPreview instance can take a significant amount of time.

Note: As you can see, we only need to have a reference to an instance of the Printable interface to create a PrintPreview component. Thus, this component can be added to any print-aware application with only a couple lines of code. We will use it in the remaining examples as well, because it is such a simple feature to add.

Class PrintPreview

This class represents a JFrame-based component which is capable of displaying the results of printing before actual printing occurs. Several instance variables are used:

Printable m_target: an object whose printout will be previewed.

int m_wPage: width of the default printing page.

int m_hPage: height of the default printing page.

JComboBox m_cbScale: combobox which selects a scale for preview.

PreviewContainer m_preview: container which holds previewing pages.

Two public constructors are provided. The first one takes an instance of the Printable interface and passes control to the second constructor, using the Printable along with the "Print Preview" String as parameters. The second constructor takes two parameters: an instance of the Printable interface and the title string for the frame. This second constructor is the one that actually sets up the PrintPreview component.

First, a toolbar is created and a button titled "Print" is added to perform printing of the m_target instance as described in the previous example. The only difference is that no Print dialog is invoked, and the default system printer is used (this approach is typical for print preview components). When the printing is complete, this print preview component is disposed. The second button added to the toolbar is labeled "Close" and merely disposes of this frame component.

The third (and the last) component added to the toolbar is the editable combobox m_cbScale, which selects a percent scale to zoom the previewed pages. Along with several pre-defined choices (10 %, 25 %, 50 %, and 100 %) any percent value can be entered. As soon as that value is selected and the corresponding ActionListener involved, the zoom scale value is extracted and stored in the local variable scale. This determines the width and height of each PreviewPage component we will be creating:

                int w = (int)(m_wPage*scale/100);

                int h = (int)(m_hPage*scale/100);

Then all child components of the m_preview container in turn are cast to PagePreview components (each child is expected to be a PagePreview instance, but instanceof is used for precaution), and the setScaledSize() method is invoked to assign a new size to the preview pages. Finally doLayout() is invoked on m_preview to lay out the resized child components, and validate() is invoked on the scroll pane. This scroll pane is the parent of the m_preview component in the second generation (the first parent is a JViewport component--see chapter 7). This last call is necessary to display/hide scroll bars as needed for the new size of the m_preview container. This whole process is wrapped in a thread to avoid clogging up the AWT event-dispatching thread.

When toolbar construction is complete, the m_preview component is created and filled with the previewed pages. To do so we first retrieve a PrinterJob instance for a default system printer without displaying a Page Setup dialog, and retrieve a default PageFormat instance. We use this to determine the initial size of the previewed pages by multiplying its dimensions by the computed scaling percentile (which is 10% at initialization time, because scale is set to 10).

To create these scalable preview pages we set up a while loop to continuously call the print() method of the given Printable instance, using a page index that gets incremented each iteration, until it returns something other than Printable.PAGE_EXISTS.

Each page is rendered into a separate image in memory. To do this, an instance of BufferedImage is created with width m_wPage and height m_hPage. A Graphics instance is retrieved from that image using getGraphics():

                BufferedImage img = new BufferedImage(m_wPage,

                    m_hPage, BufferedImage.TYPE_INT_RGB);

                Graphics g = img.getGraphics();

                g.setColor(Color.white);

                g.fillRect(0, 0, m_wPage, m_hPage);

                if (target.print(g, pageFormat, pageIndex) !=

                    Printable.PAGE_EXISTS)

                    break;

After filling the image's area with a white background (most paper is white), this Graphics instance, along with the PageFormat and current page index, pageIndex, are passed to the print() method of the Printable object.

Note: The BufferedImage class in the java.awt.image package allows direct image manipulation in memory. This class will be discussed in more detail in Chapter 23, as well as other classes from the Java 2 2D API.

If the call to the print() method returns PAGE_EXISTS, indicating success in the rendering of the new page, a new PagePreview component is created:

                PagePreview pp = new PagePreview(w, h, img);

                m_preview.add(pp);

                pageIndex++;

Note that our newly created BufferedImage is passed to the PagePreview constructor as one of the parameters. This is so that we can use it now and in the future for scaling each PagePreview component separately. The other parameters are the width and height to use, which, at creation time, are 10% of the page size (as discussed above).

Each new component is added to our m_preview container. Finally, when the Printable's print() method finishes, our m_preview container is placed in a JScrollPane to provide scrolling capabilities. This scroll pane is then added to the center of the PrintPreview frame, and our frame is then made visible.

Class PrintPreview.PreviewContainer

This inner class extends JPanel to serve as a container for PagePreview components. The only reason this custom container is developed is because we have specific layout requirements. What we want here is a layout which places its child components from left to right, without any resizing (using their preferred size), and leaves equal gaps between them. When the available container's width is filled, a new row should be started from the left edge, without regard to the available height (we assume scrolling functionality will be made available).

You may want to refer back to our discussion of layouts in chapter 4. The code constituting this class does not require much explanation and provides a good exercise for custom layout development (even though this class is not explicitly a layout manager).

Class PrintPreview.PagePreview

This inner class extends JPanel to serve as a placeholder for the image of each printed page preview. Four instance variables are used:

int m_w: the current component's width (without insets).

int m_h: the current component's height (without insets).

Image m_source: the source image depicting the previewed page in full scale.

Image m_img: the scaled image currently used for rendering.

The constructor of the PagePreview class takes its initial width, height, and the source image. It creates a scaled image by calling the getScaledInstance() method and sets its border to MatteBorder(1, 1, 2, 2, Color.black) to imitate a page laying on a flat surface.

The setScaledSize() method may be called to resize this component. It takes a new width and height as parameters and creates a new scaled image corresponding to the new size. Usage of the SCALE_SMOOTH option for scaling is essential to get a preview image which looks like a zoomed printed page (although it is not the fastest option).

The paint() method draws a scaled image and draws a border around the component.

Running the Code

At this point you can compile and execute this example. Figure 22.2 shows a preview of the large image which will be printed on the nine pages. Select various zoom factors in the combobox and see how the size of the previewed pages is changed. Then press the "Print" button to print to the default printer directly from the preview frame.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy