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