Printing Text

The trick to printing text is to measure it and compare it to the page size and resolution in a given font. You do this with the java.awt.FontMetrics class.

// This example is adapted
// from the book _Java AWT Reference_ by John Zukowski.
// Written by John Zukowski.  Copyright (c) 1997 O'Reilly & Associates.
// You may study, use, modify, and distribute this example for any purpose.
// This example is provided WITHOUT WARRANTY either expressed or implied

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Properties;

public class TestPrint extends Frame {
    
  private TextArea textArea = new TextArea (10, 40);
  private Label    statusInfo = new Label();
  private Button   loadButton;
  private Button   printButton; 
  private Button   closeButton;
  private Properties p = new Properties();
    
  public TestPrint() {
  
    super ("File Loader");
    this.add(statusInfo, "North");
    Panel p = new Panel ();
    p.add(loadButton = new Button ("Load"));
    loadButton.addActionListener( new LoadFileCommand() );
    p.add(printButton = new Button ("Print"));
    printButton.addActionListener( new PrintCommand() );
    p.add(closeButton = new Button ("Close"));
    closeButton.addActionListener( new CloseCommand() );        
    this.add(p, "South");
    this.add(textArea, "Center");
    this.pack();
    
  }
  
  
  public static void main (String args[]) {
    TestPrint f = new TestPrint();
    f.show();
  }

  // Bail Out
  class CloseCommand implements ActionListener {
    public void actionPerformed (ActionEvent evt) {
      System.exit(0);
    }
  }
    
  // Load a file into the text area.
  class LoadFileCommand implements ActionListener {
    public void actionPerformed (ActionEvent evt) {
      int state;
      String msg;
      FileDialog file = new FileDialog (TestPrint.this, "Load File", FileDialog.LOAD);
      file.setFile("*.java");  // Set initial filename filter
      file.show(); // Blocks
      String curFile;
      if ((curFile = file.getFile()) != null) {
        String filename = file.getDirectory() + curFile;
        char[] data;
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        File f = new File (filename);
        try {
          FileReader fin = new FileReader (f);
          int filesize = (int) f.length();
          data = new char[filesize];
          fin.read(data, 0, filesize);
        } 
        catch (FileNotFoundException ex) {
          String errorString = "File Not Found: " + filename;
          data = errorString.toCharArray ();
        } 
        catch (IOException ex) {
          String errorString = "IOException: " + filename;
          data = errorString.toCharArray ();
        }
        statusInfo.setText("Load: " + filename);
        textArea.setText(new String (data));
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }
    }
  }

  // Print a file into the text area.
  class PrintCommand implements ActionListener {
    public void actionPerformed (ActionEvent evt) {
      PrintJob pjob = getToolkit().getPrintJob(TestPrint.this, "Cool Stuff", p);
      if (pjob != null) {
        Graphics pg = pjob.getGraphics();
        if (pg != null) {
          String s = textArea.getText();
          printLongString(pjob, pg, s);
          pg.dispose();
        }
        pjob.end();
      }
    }
  }

  // I'm assuming a one-inch margin on all
  // four sides. This could be done better.
  private int margin = 72;
  
  // Print string to graphics via printjob
  // Does not deal with word wrap or tabs
  private void printLongString (PrintJob pjob, Graphics pg, String s) {
      
    int pageNum = 1;
    int linesForThisPage = 0;
    int linesForThisJob = 0;
    // Note: String is immutable so won't change while printing.
    if (!(pg instanceof PrintGraphics)) {
      throw new IllegalArgumentException ("Graphics context not PrintGraphics");
    }
    StringReader sr = new StringReader(s);
    LineNumberReader lnr = new LineNumberReader (sr);
    String nextLine;
    int pageHeight = pjob.getPageDimension().height - margin;
    Font helv = new Font("Helvetica", Font.PLAIN, 12);
    //have to set the font to get any output
    pg.setFont (helv);
    FontMetrics fm = pg.getFontMetrics(helv);
    int fontHeight = fm.getHeight();
    int fontDescent = fm.getDescent();
    int curHeight = margin;
    try {
      do {
        nextLine = lnr.readLine();
        if (nextLine != null) {         
          if ((curHeight + fontHeight) > pageHeight) {
            // New Page
            System.out.println(linesForThisPage + " lines printed for page " + pageNum);
            if(linesForThisPage == 0) {
               System.out.println(
                 "Font is too big for pages of this size; aborting...");
               break;
            }
            pageNum++;
            linesForThisPage = 0;
            pg.dispose();
            pg = pjob.getGraphics();
            if (pg != null) {
              pg.setFont(helv);
            }
            curHeight = 0;
          }
          curHeight += fontHeight;
          if (pg != null) {
            pg.drawString(nextLine, margin, curHeight - fontDescent);
            linesForThisPage++;
            linesForThisJob++;
          } 
          else {
            System.out.println("pg null");
          }
        }
      } while (nextLine != null);
    } 
    catch (EOFException eof) {
      // Fine, ignore
    } 
    catch (Throwable t) { // Anything else
      t.printStackTrace();
    }
    System.out.println("" + linesForThisPage + " lines printed for page " + pageNum);
    System.out.println("pages printed: " + pageNum);
    System.out.println("total lines printed: " + linesForThisJob);
  }
  
}

Open question: how do you determine the printable area of the page? i.e. what are the mandatory margins?


Previous | Next | Top | Cafe au Lait

Copyright 1997, 2002, 2006 Elliotte Rusty Harold
elharo@metalab.unc.edu
Last Modified April 25, 2006