Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

Printing of a multi-page book

/*    This program is a part of the companion code for Core Java 8th ed.    (http://horstmann.com/corejava)    This program is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program.  If not, see <http://www.gnu.org/licenses/>. */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.print.Book; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; /**  * This program demonstrates the printing of a multi-page book. It prints a "banner", by blowing up  * a text string to fill the entire page vertically. The program also contains a generic print  * preview dialog.  * @version 1.12 2007-08-16  * @author Cay Horstmann  */ public class BookTest {    public static void main(String[] args)    {       EventQueue.invokeLater(new Runnable()          {             public void run()             {                JFrame frame = new BookTestFrame();                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                frame.setVisible(true);             }          });    } } /**  * This frame has a text field for the banner text and buttons for printing, page setup, and print  * preview.  */ class BookTestFrame extends JFrame {    public BookTestFrame()    {       setTitle("BookTest");       text = new JTextField();       add(text, BorderLayout.NORTH);       attributes = new HashPrintRequestAttributeSet();       JPanel buttonPanel = new JPanel();       JButton printButton = new JButton("Print");       buttonPanel.add(printButton);       printButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                try                {                   PrinterJob job = PrinterJob.getPrinterJob();                   job.setPageable(makeBook());                   if (job.printDialog(attributes))                   {                      job.print(attributes);                   }                }                catch (PrinterException e)                {                   JOptionPane.showMessageDialog(BookTestFrame.this, e);                }             }          });       JButton pageSetupButton = new JButton("Page setup");       buttonPanel.add(pageSetupButton);       pageSetupButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                PrinterJob job = PrinterJob.getPrinterJob();                pageFormat = job.pageDialog(attributes);             }          });       JButton printPreviewButton = new JButton("Print preview");       buttonPanel.add(printPreviewButton);       printPreviewButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                PrintPreviewDialog dialog = new PrintPreviewDialog(makeBook());                dialog.setVisible(true);             }          });       add(buttonPanel, BorderLayout.SOUTH);       pack();    }    /**     * Makes a book that contains a cover page and the pages for the banner.     */    public Book makeBook()    {       if (pageFormat == null)       {          PrinterJob job = PrinterJob.getPrinterJob();          pageFormat = job.defaultPage();       }       Book book = new Book();       String message = text.getText();       Banner banner = new Banner(message);       int pageCount = banner.getPageCount((Graphics2D) getGraphics(), pageFormat);       book.append(new CoverPage(message + " (" + pageCount + " pages)"), pageFormat);       book.append(banner, pageFormat, pageCount);       return book;    }    private JTextField text;    private PageFormat pageFormat;    private PrintRequestAttributeSet attributes; } /**  * A banner that prints a text string on multiple pages.  */ class Banner implements Printable {    /**     * Constructs a banner     * @param m the message string     */    public Banner(String m)    {       message = m;    }    /**     * Gets the page count of this section.     * @param g2 the graphics context     * @param pf the page format     * @return the number of pages needed     */    public int getPageCount(Graphics2D g2, PageFormat pf)    {       if (message.equals("")) return 0;       FontRenderContext context = g2.getFontRenderContext();       Font f = new Font("Serif", Font.PLAIN, 72);       Rectangle2D bounds = f.getStringBounds(message, context);       scale = pf.getImageableHeight() / bounds.getHeight();       double width = scale * bounds.getWidth();       int pages = (int) Math.ceil(width / pf.getImageableWidth());       return pages;    }    public int print(Graphics g, PageFormat pf, int page) throws PrinterException    {       Graphics2D g2 = (Graphics2D) g;       if (page > getPageCount(g2, pf)) return Printable.NO_SUCH_PAGE;       g2.translate(pf.getImageableX(), pf.getImageableY());       drawPage(g2, pf, page);       return Printable.PAGE_EXISTS;    }    public void drawPage(Graphics2D g2, PageFormat pf, int page)    {       if (message.equals("")) return;       page--; // account for cover page       drawCropMarks(g2, pf);       g2.clip(new Rectangle2D.Double(0, 0, pf.getImageableWidth(), pf.getImageableHeight()));       g2.translate(-page * pf.getImageableWidth(), 0);       g2.scale(scale, scale);       FontRenderContext context = g2.getFontRenderContext();       Font f = new Font("Serif", Font.PLAIN, 72);       TextLayout layout = new TextLayout(message, f, context);       AffineTransform transform = AffineTransform.getTranslateInstance(0, layout.getAscent());       Shape outline = layout.getOutline(transform);       g2.draw(outline);    }    /**     * Draws 1/2" crop marks in the corners of the page.     * @param g2 the graphics context     * @param pf the page format     */    public void drawCropMarks(Graphics2D g2, PageFormat pf)    {       final double C = 36; // crop mark length = 1/2 inch       double w = pf.getImageableWidth();       double h = pf.getImageableHeight();       g2.draw(new Line2D.Double(0, 0, 0, C));       g2.draw(new Line2D.Double(0, 0, C, 0));       g2.draw(new Line2D.Double(w, 0, w, C));       g2.draw(new Line2D.Double(w, 0, w - C, 0));       g2.draw(new Line2D.Double(0, h, 0, h - C));       g2.draw(new Line2D.Double(0, h, C, h));       g2.draw(new Line2D.Double(w, h, w, h - C));       g2.draw(new Line2D.Double(w, h, w - C, h));    }    private String message;    private double scale; } /**  * This class prints a cover page with a title.  */ class CoverPage implements Printable {    /**     * Constructs a cover page.     * @param t the title     */    public CoverPage(String t)    {       title = t;    }    public int print(Graphics g, PageFormat pf, int page) throws PrinterException    {       if (page >= 1) return Printable.NO_SUCH_PAGE;       Graphics2D g2 = (Graphics2D) g;       g2.setPaint(Color.black);       g2.translate(pf.getImageableX(), pf.getImageableY());       FontRenderContext context = g2.getFontRenderContext();       Font f = g2.getFont();       TextLayout layout = new TextLayout(title, f, context);       float ascent = layout.getAscent();       g2.drawString(title, 0, ascent);       return Printable.PAGE_EXISTS;    }    private String title; } /**  * This class implements a generic print preview dialog.  */ class PrintPreviewDialog extends JDialog {    /**     * Constructs a print preview dialog.     * @param p a Printable     * @param pf the page format     * @param pages the number of pages in p     */    public PrintPreviewDialog(Printable p, PageFormat pf, int pages)    {       Book book = new Book();       book.append(p, pf, pages);       layoutUI(book);    }    /**     * Constructs a print preview dialog.     * @param b a Book     */    public PrintPreviewDialog(Book b)    {       layoutUI(b);    }    /**     * Lays out the UI of the dialog.     * @param book the book to be previewed     */    public void layoutUI(Book book)    {       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);       canvas = new PrintPreviewCanvas(book);       add(canvas, BorderLayout.CENTER);       JPanel buttonPanel = new JPanel();       JButton nextButton = new JButton("Next");       buttonPanel.add(nextButton);       nextButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                canvas.flipPage(1);             }          });       JButton previousButton = new JButton("Previous");       buttonPanel.add(previousButton);       previousButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                canvas.flipPage(-1);             }          });       JButton closeButton = new JButton("Close");       buttonPanel.add(closeButton);       closeButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                setVisible(false);             }          });       add(buttonPanel, BorderLayout.SOUTH);    }    private PrintPreviewCanvas canvas;    private static final int DEFAULT_WIDTH = 300;    private static final int DEFAULT_HEIGHT = 300; } /**  * The canvas for displaying the print preview.  */ class PrintPreviewCanvas extends JComponent {    /**     * Constructs a print preview canvas.     * @param b the book to be previewed     */    public PrintPreviewCanvas(Book b)    {       book = b;       currentPage = 0;    }    public void paintComponent(Graphics g)    {       Graphics2D g2 = (Graphics2D) g;       PageFormat pageFormat = book.getPageFormat(currentPage);       double xoff; // x offset of page start in window       double yoff; // y offset of page start in window       double scale; // scale factor to fit page in window       double px = pageFormat.getWidth();       double py = pageFormat.getHeight();       double sx = getWidth() - 1;       double sy = getHeight() - 1;       if (px / py < sx / sy) // center horizontally       {          scale = sy / py;          xoff = 0.5 * (sx - scale * px);          yoff = 0;       }       else       // center vertically       {          scale = sx / px;          xoff = 0;          yoff = 0.5 * (sy - scale * py);       }       g2.translate((float) xoff, (float) yoff);       g2.scale((float) scale, (float) scale);       // draw page outline (ignoring margins)       Rectangle2D page = new Rectangle2D.Double(0, 0, px, py);       g2.setPaint(Color.white);       g2.fill(page);       g2.setPaint(Color.black);       g2.draw(page);       Printable printable = book.getPrintable(currentPage);       try       {          printable.print(g2, pageFormat, currentPage);       }       catch (PrinterException e)       {          g2.draw(new Line2D.Double(0, 0, px, py));          g2.draw(new Line2D.Double(px, 0, 0, py));       }    }    /**     * Flip the book by the given number of pages.     * @param by the number of pages to flip by. Negative values flip backwards.     */    public void flipPage(int by)    {       int newPage = currentPage + by;       if (0 <= newPage && newPage < book.getNumberOfPages())       {          currentPage = newPage;          repaint();       }    }    private Book book;    private int currentPage; }