Printout.java — Java Text Printing Demo

 

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;
      }
   }
}