Download Printout.java source file
// This class supports printing of the text in a JTextArea. // Just hook up buttons or menu items to the three show.., methods. // If the banner constructor argument is null, no print job (banner) page is // printed. Page preview is complex, to be added in a future version! // Also and "reset" method in future. // // Written 8/2005 by Wayne Pollock, Tampa Florida USA. // Adapted from sample code in "Core Java 2 vol. 2", 7th edition, pp. 539-575 // by Cay Horstmann and Gary Cornell, (C)2005 Prentice-Hall PTR. package com.wpollock.loan; import java.awt.*; import java.awt.geom.*; import javax.swing.*; import java.awt.print.*; // Printable, Pageable, PrinterJob, PageFormat, Book import java.awt.font.*; // TextLayout // Needed for Java PrintDialog; not needed if using native dialog: import javax.print.attribute.*; // PrintRequestAttributeSet //import javax.print.*; // To support document printing (DocPrintJob) public class Printout { private PrintRequestAttributeSet attributes = null; private PageFormat pageFormat = null; private PrinterJob job = null; private Book book = null; private JTextArea jta = null; private String bannerText = null; private String pageHeaderText = null; private String pageFooterText = null; public Printout ( JTextArea newJta, String banner ) // header, footer: ver 2 { jta = newJta; bannerText = banner; job = PrinterJob.getPrinterJob(); attributes = new HashPrintRequestAttributeSet(); pageFormat = job.defaultPage(); book = new Book(); } public void showPrintPreview () // for version 2 { throw new UnsupportedOperationException( "Feature Not Available." ); } public void showPageSetup () { pageFormat = job.pageDialog( pageFormat ); // Show native dialog. // pageFormat = job.pageDialog( attributes ); // Show Java dialog. } public void showPrintDialog () { int totalNumPagesToPrint = 0; BannerPage bannerPage = null; Section section = null; try { // Add a one page Printable section: if ( bannerText != null ) { bannerPage = new BannerPage( bannerText ); book.append( bannerPage, pageFormat ); // A single page section totalNumPagesToPrint = book.getNumberOfPages(); } // Add a multi-page Printable section: // Each section must be able to calculate the number of its first page // in the book (Pageable). This is because the Printable.print method // is passed the whole book's page number, not the current section's // page number. Note page numbers start at zero, not one. // In the next version, also pass in the page header and footer text. section = new Section( jta, totalNumPagesToPrint ); book.append( section, pageFormat, section.getPageCount() ); totalNumPagesToPrint = book.getNumberOfPages(); // ... Repeat to print additional sections if ( bannerPage != null ) bannerPage.setTotalPageCount( totalNumPagesToPrint ); job.setPageable( book ); // // Show Java print dialog, print unless cancelled (returns false): // if ( job.printDialog( attributes ) ) // job.print( attributes ); // Show Native print dialog, print unless cancelled (returns false): if ( job.printDialog() ) job.print( attributes ); // To print without a dialog, use: // job.print(); // OR: job.print( attributes ); } catch ( PrinterException e ) { JOptionPane.showMessageDialog( null, e ); } } } class BannerPage implements Printable { private String bannerText = null; private int totalPageCount = -1; // the "-1" means don't use. private Font font = new Font( "SansSerif", Font.BOLD | Font.ITALIC, 36 ); public int getPageCount () { return 1; // The banner page is a single page. } public void setTotalPageCount ( int count ) { totalPageCount = count; } public BannerPage ( String newBannerText ) { bannerText = newBannerText; } public int print ( Graphics g, PageFormat pf, int bookPageNumber ) { if ( bookPageNumber >= 1 ) return Printable.NO_SUCH_PAGE; Graphics2D g2 = (Graphics2D) g; // Reset the 0,0 point for the page: g2.translate( pf.getImageableX(), pf.getImageableY() ); // Draw the cover (the only) page: drawPage( g2 ); return Printable.PAGE_EXISTS; } // Draw (single) cover page: public void drawPage ( Graphics2D g ) { g.setPaint( Color.BLACK ); g.setFont( font ); // Draw fancy huge banner: FontRenderContext frc = g.getFontRenderContext(); TextLayout layout = new TextLayout( bannerText, font, frc ); float yPos = layout.getAscent(); g.drawString( bannerText, 0, yPos ); String pageCount = null; if ( totalPageCount > 0 ) pageCount = "(" + totalPageCount + " pages)"; float fontSize = font.getSize2D() / 2; layout = new TextLayout( pageCount, font.deriveFont( fontSize ), frc ); yPos = 2 * yPos + layout.getAscent(); g.drawString( pageCount, 0, yPos ); } } class Section implements Printable { // Num points added to the maximum ascent of the font, to set line spacing: private final int INTER_LINE_SPACE = 2; private int pageCount = 0; // Must calculate this. private int bookPageNumberOffset; // This is the first (cover) page. private Font font = null; private String text = null; private double scaleFactor = 1.0; public int getPageCount () { return pageCount; } public Section ( JTextArea jta, int offset ) { font = jta.getFont(); text = jta.getText(); bookPageNumberOffset = offset; } public int print ( Graphics g, PageFormat pf, int bookPageNumber ) { int pageNumber = bookPageNumber - bookPageNumberOffset; if ( pageNumber >= pageCount ) return Printable.NO_SUCH_PAGE; // Draw the correct page from this Printable section: Graphics2D g2 = (Graphics2D) g; drawPage( g2, pf, pageNumber ); return Printable.PAGE_EXISTS; } // Draw each page of this Printable section: public void drawPage ( Graphics2D g, PageFormat pf, int pageNum ) { double pageWidth = pf.getImageableWidth(); double pageHeight = pf.getImageableHeight(); int lineHeight = g.getFontMetrics().getMaxAscent() + INTER_LINE_SPACE; int linesPerPage = (int) Math.ceil( pageHeight / lineHeight ); String [] lines = text.split( "\n" ); // Reset the 0,0 point for the page to the upper-leftmost // printable point: g.translate( pf.getImageableX(), pf.getImageableY() ); // Render giant graphic of all pages. Here's where you can get fancy, // say by putting a header/footer on each page. In this version we // break the text into lines by locating the newline character, render // that line, and move on to the next. If a line is too wide to fit, // we can either ignore it (yes), fold the line onto a new line, or scale // the page. By tracking the widest line in the document we can // compute a scale factor to force the text to fit one page wide. // We need to track if some line won't fit on the current // page, in wich case you need to skip to the next page, so lines // don't get split across pages. // Clip the graphic to only draw a single page: g.clip( new Rectangle2D.Double( 0.0, 0.0, pageWidth, pageHeight ) ); // Translate the graphic (up) so the proper page is in the clip area: g.translate( 0.0, -pageNum * pageHeight ); g.setPaint( Color.BLACK ); g.setFont( font ); for ( int yPos = 0, lineNum = 0; lineNum < lines.length; ++lineNum ) { if ( lineNum % linesPerPage == 0 ) { yPos = (int) Math.ceil( pageCount * pageHeight + lineHeight ); ++pageCount; } g.drawString( lines[lineNum], 0, yPos ); yPos += lineHeight; } } }