Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Printing with AWT and Swing

Java Programming, Lecture Notes # 108, Revised 11/02/98.


Preface

Students in Prof. Baldwin's Intermediate Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.

This lesson was originally written on May 8, 1998, using the software and documentation in the JDK 1.1.6 and Swing 1.0.1 download packages.

Introduction

In an earlier lesson, we learned about the Toolkit class.  We learned that the Toolkit class provides a platform-independent interface to platform-specific services such as printing, fonts, images, and display parameters.

The Toolkit constructor is abstract and therefore, we never directly instantiate an object of type Toolkit. Rather, we obtain a Toolkit object by invoking the getDefaultToolkit() method. This gives us an object that is appropriate for our system.

There are many methods in the Toolkit class. The method that is of primary interest in this program is shown below.

getPrintJob() - Gets a PrintJob object to use for printing 

There are at least two different ways to print in Java.  One way is to get a Graphics object that represents the paper in the printer and draw or paint on that object.

The other way is to ask a component to print itself and all of the components that it contains using the printAll() method.  Either of these methods should work for both AWT and Swing components.  However, as of 5/7/98, there is a bug that prevents printAll() from working properly with Swing 1.0.1 and JDK 1.1.6 under Win95.

This lesson contains three sample programs which illustrate the two different ways to print, both with AWT and Swing

Sample Program using printAll Method

The purpose of this program is to demonstrate the ability to print the components in an AWT container that is either a top-level container, or is embedded inside another AWT container.

Even though this application only works with AWT components, it is hoped that it can be made to work with Swing components once the bugs are all worked out of Swing and the JDK.

This program places one of two selectable Panel objects and four Button objects in a Frame object.

One of the buttons has a listener that causes the currently selected Panel and all the components contained in the Panel to be printed. (See comment below regarding the printing of the Panel.)

Another of the buttons has a listener that causes the top-level Frame container and all the components contained in the Frame to be printed.

Actually, with JDK 1.1.6 under Win95, the Frame itself isn't printed.  Only its contents are printed.  This seems to contradict the specifications for the printAll() method in the JavaSoft documentation which contains the following description of the printAll() method: 

"Prints this component and all of its subcomponents."

The same is probably true for the Panel, but a Panel doesn't have any distinguishing characteristics that would make it apparent that it is or isn't being printed.

Both of the above mentioned buttons actually share the same listener object, but the end result is as described above.

The other two buttons are used to select between two different Panel objects.  In other words, the user can select between two different panels and cause the one currently installed in the Frame to be printed.

When the selected Panel is printed, the other components in the Frame are ignored.

When the Frame is printed, all of the components in the Frame, including the currently installed Panel, are printed.

Simply for illustration, one of the selectable Panel objects contains a Label, a TextField, and a Button that is not active.

The other selectable Panel contains a Label, a TextField and two Button objects that are not active.

This program was tested using JDK 1.1.6 under Win95

Interesting Code Fragments for printAll Method

This section contains a number of interesting code fragments along with explanations of those fragments.  A complete listing of the program which shows all of the fragments in context is provided in a later section.

Just to start things off, the first fragment shows the controlling class, containing a main() method that instantiates an object of the GUI class.  The object of the GUI class actually appears on the screen.

public class Print04 {
  public static void main(String[] args){
    GUI gui = new GUI();
  }//end main
}//end class Print04

The next fragment shows the beginning of the GUI class, including the declaration of several reference variables.

The container named myFrame and all of the components that it contains will be printed or sent to a print file when the Button with the caption "Print the Frame" is clicked. (With JDK 1.1.6, only the components that it contains are printed. I don't know if this is a bug or an interpretation issue regarding the specifications for the method named printAll.)

The container named panelToPrint and all of the components that it contains will be printed or sent to a print file when the Button with the caption "Print the Panel" is clicked. (With JDK 1.1.6, it is probable that only the components that it contains are printed but this is not obvious because a Panel has no distinguishing features that would cause the viewer to be able to determine if the Panel is printed or not.)

The references to the two Panel objects are references to the two selectable panels.

class GUI{
  Frame myFrame = new Frame("Copyright 1997, R.G.Baldwin");
  Panel panelToPrint = null;
  
  //References to two selectable panels
  Panel panel0;
  Panel panel1;

The following fragment shows the beginning of the constructor for the GUI object.  It also shows a number of components being instantiated and added to the Frame.  By now, this should be "old stuff" to you so I won't waste your time with an explanation.  The material is being included in this section only for the purpose of providing continuity.

    
  public GUI(){//constructor
    //The following buttons cause the Panel and Frame
    // containers to be printed.
    Button printPanelButton = new Button("Print the Panel");
    printPanelButton.addActionListener(
                                new PrintActionListener());
    myFrame.add(printPanelButton,"North");
    
    Button printFrameButton = new Button("Print the Frame");
    printFrameButton.addActionListener(
                                new PrintActionListener());
    myFrame.add(printFrameButton,"South");
    
    //The following buttons are used to select between two
    // different panels for display
    Button selectPanel0Button = 
                              new Button("Select Panel 0");
    selectPanel0Button.addActionListener(
                               new SelectPanel0Listener());
    myFrame.add(selectPanel0Button,"West");
    
    Button selectPanel1Button = 
                              new Button("Select Panel 1");
    selectPanel1Button.addActionListener(
                               new SelectPanel1Listener());
    myFrame.add(selectPanel1Button,"East");

Code in the following fragment is used to construct the selectable Panel objects that will be assigned to the panelToPrint reference when a selection is made. The print routine causes the container referenced by panelToPrint and all of its components to be printed. (See earlier comments regarding whether the container or just its contents should be printed.)

Again, this code should be very familiar to you by now and is being included here simply to provide continuity.  Some additional code that should be familiar to you was omitted for brevity, and that is the end of the GUI constructor.

    panel0 = new Panel();
    Label panel0Label = new Label("Panel 0");
    panel0.add(panel0Label);
    TextField panel0TextField = new TextField("TextField");
    panel0.add(panel0TextField);
    panel0.add(new Button("Dummy Button"));
    panel0.setBackground(Color.yellow);
    
    panel1 = new Panel();
    Label panel1Label = new Label("Panel 1");
    panel1.add(panel1Label);
    TextField panel1TextField = new TextField("TextField");
    panel1.add(panel1TextField);
    panel1.add(new Button("One Dummy Button"));
    panel1.add(new Button("Another Dummy Button"));
    panel1.setBackground(Color.pink);

    // code omitted here
  }//end constructor

The code beginning is the next fragment is what this lesson is all about. This code begins the definition of an inner class of the GUI class that is used to cause the Panel referenced by panelToPrint or the Frame referenced by myFrame to be printed.

This class is an action listener class and the code inside the actionPerformed() method actually causes the printing to take place.

Because of the importance of this code to this lesson, we will break it up into small fragments and discuss each fragment in some detail.

The first fragment is used to get a PrintJob object.  This causes the system-standard print dialog to appear on the screen.  If the user closes the dialog without allowing printing, the getPrintJob() method will return null.

On most systems, the standard print dialog allows the user to specify the printer that is to receive the material, select the print quality, send the material to a print file, or make other standard selections regarding printing on that system.

  class PrintActionListener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      PrintJob myPrintJob = myFrame.getToolkit().
            getPrintJob(
              myFrame, "Copyright 1998 R.G.Baldwin", null);

As mentioned above, the user can cause the getPrintJob() method to return null.  Therefore, the following fragments begins with a test for null and if not null, proceeds with the printing process.

The first step is to use the getGraphics() method to get a Graphics object that can probably be thought of as representing the paper in the printer.  This object is required as a parameter for the printAll() method that is invoked shortly thereafter.

A test is performed to confirm that a valid Graphics object was obtained, and if true, the program proceeds with the printing process.

The next requirement in this program is to determine which component is to be printed:

This is accomplished by invoking the getActionCommand() method on the incoming ActionEvent object to identify the source of the event.

Then, depending on the source, the printAll() method is invoked on either the Panel or the Frame, passing the Graphics object as a parameter.

As discussed earlier, the JavaSoft documentation for JDK 1.1.6 indicates that this will cause the container on which the method is invoked and all of the components that it contains to be printed on the printer.  Also, as mentioned earlier, in JDK 1.1.6 under Win95, only the components that it contains are actually printed.  The container is not printed.

Since the system is actually painting graphics components onto the paper, the quality will depend on the printer being used.  For the components being used in this sample program, the quality is actually quite good on a Cannon BJC-4000 printer operating in black-and-white mode.

      if(myPrintJob != null){
        Graphics printGraphics = myPrintJob.getGraphics();
        if(printGraphics != null){
          if(e.getActionCommand().equals("Print the Panel"))
            panelToPrint.printAll(printGraphics);
          else myFrame.printAll(printGraphics);

After the material is painted on the paper, we need to force a form feed on the printer to eject the paper. We also need to free up the resources that are tied up by the Graphics object.  This is accomplished by invoking the dispose() method on the Graphics object as shown in the following code fragment.

This fragment also invokes the end() method on the PrintJob object, which, according to the JavaSoft documentation in JDK 1.1.6:

"Ends the print job and does any necessary cleanup."

This fragment also shows the else side of a couple of earlier if statements that were used to confirm that the PrintJob and Graphics objects were valid.  If they were not valid, the printing process is aborted with some messages displayed on the screen (would probably be better to throw an exception).

          printGraphics.dispose();
        }//end if statement
        else 
          System.out.println(
                       "Didn't get print graphics object");
        myPrintJob.end();
      }//end if statement
      else 
        System.out.println("PrintJob cancelled by user");
    }//end actionPerformed()
  }//end class PrintActionListener

The program contains two additional ActionListener class definitions that are used to control the process of selecting one of two Panel objects for display.  Since that is not really the thrust of this lesson, a discussion of these classes  will not be provided in this section.  However, there is some important information provided there that is not provided in other lessons of this tutorial.  You should take the opportunity to study those classes in the complete program listing that follows.

Program Listing for printAll Method

This section contains a complete listing of the program. The lesson resumes following this section with a discussion of a printing program that paints material on the paper using AWT.

/*File Print04.java
Copyright 1998 R.G.Baldwin

The purpose of this program is to demonstrate the ability
to print the components in an AWT container that
is either a top-level container, or is embedded inside 
another AWT container.

Even though this application only works with AWT 
components, it is hoped that it can be made to work with
Swing components once the bugs are all worked out of Swing
and the JDK.

This program places one of two selectable Panels and four
Buttons in a Frame.

One of the buttons has a listener that causes the currently
selected Panel and all the components contained in the 
Panel to be printed. (See comment below regarding the 
printing of the Panel.)

Another of the buttons has a listener that causes the
top-level Frame container and all the components contained
in the Frame to be printed. 

Actually, with JDK 1.1.6 under Win95, the Frame itself
isn't printed.  Only its contents are printed.  This seems
to contradict the specifications for the printAll()
method in the JavaSoft documentation which contains the
following description of the printAll() method:
  
"Prints this component and all of its subcomponents."  

The same is probably true for the Panel, but a Panel
doesn't have any distinguishing characteristics that would
make it apparent that it is or isn't being printed.
  
Both of the above mentioned buttons actually share
the same listener object, but the end result is as 
described above.

The other two buttons are used to select between two 
different Panels.  In other words, the user can select
between two different panels and cause the one currently
installed in the Frame to be printed.

When the selected Panel is printed, the other components in
the Frame are ignored.

When the Frame is printed, all of the components in the
Frame, including the currently installed Panel, are 
printed.

Simply for illustration, one of the selectable Panels 
contains a Label, a TextField, and a Button that is not 
active.

The other selectable Panel contains a Label, a TextField 
and two Buttons that are not active.

Tested using JDK 1.1.6 under Win95
**********************************************************/

import java.awt.*;
import java.awt.event.*;
//=======================================================//

public class Print04 {
  public static void main(String[] args){
    //instantiate a Graphical User Interface object
    GUI gui = new GUI();
  }//end main
}//end class Print04
//=======================================================//

//This class is used to instantiate a Graphical User
// Interface object
class GUI{
  //The container named myFrame and all of the
  // components that it contains will be printed or sent
  // to a print file when the Button with the caption
  // "Print the Frame" is clicked. (With JDK 1.1.6, only
  // the components that it contains are printed. Don't
  // know if this is a bug or an interpretation issue
  // regarding the specifications for the method named
  // printAll().) 
  Frame myFrame = new Frame("Copyright 1997, R.G.Baldwin");
  
  //The container named panelToPrint and all of the
  // components that it contains will be printed or sent
  // to a print file when the Button with the caption
  // "Print the Panel" is clicked. (With JDK 1.1.6, it is
  // probable that only the components that it contains are
  // printed but this is not obvious because a Panel has
  // no distinguishing features that would cause the 
  // viewer to be able to determine if the Panel is printed
  // or not.) 
  Panel panelToPrint = null;
  
  //References to two selectable panels
  Panel panel0;
  Panel panel1;
    
  public GUI(){//constructor
    //The following button causes the panelToPrint
    // container to be printed.
    Button printPanelButton = new Button("Print the Panel");
    printPanelButton.addActionListener(
                                new PrintActionListener());
    myFrame.add(printPanelButton,"North");
    
    Button printFrameButton = new Button("Print the Frame");
    printFrameButton.addActionListener(
                                new PrintActionListener());
    myFrame.add(printFrameButton,"South");
    
    //The following buttons are used to select between two
    // different panels for display
    Button selectPanel0Button = 
                              new Button("Select Panel 0");
    selectPanel0Button.addActionListener(
                               new SelectPanel0Listener());
    myFrame.add(selectPanel0Button,"West");
    
    Button selectPanel1Button = 
                              new Button("Select Panel 1");
    selectPanel1Button.addActionListener(
                               new SelectPanel1Listener());
    myFrame.add(selectPanel1Button,"East");

    //Construct the selectable Panels that will be assigned
    // to the panelToPrint reference when a selection is
    // made.  The print routine causes the container 
    // referenced by panelToPrint and all of its components
    // to be printed. (See earlier comments regarding 
    // whether the container or just its contents should
    // be printed.)
    panel0 = new Panel();
    Label panel0Label = new Label("Panel 0");
    panel0.add(panel0Label);
    TextField panel0TextField = new TextField("TextField");
    panel0.add(panel0TextField);
    panel0.add(new Button("Dummy Button"));
    panel0.setBackground(Color.yellow);
    
    panel1 = new Panel();
    Label panel1Label = new Label("Panel 1");
    panel1.add(panel1Label);
    TextField panel1TextField = new TextField("TextField");
    panel1.add(panel1TextField);
    panel1.add(new Button("One Dummy Button"));
    panel1.add(new Button("Another Dummy Button"));
    panel1.setBackground(Color.pink);

    //Need a valid reference in panelToPrint to prevent a
    // null pointer exception when a selection is made and
    // an attempt is made to remove the old reference.
    panelToPrint = panel0;

    myFrame.setSize(340,200);
    myFrame.setVisible(true);

    //This is an anonymous inner class of the GUI class 
    // used to terminate the program when the user closes
    // the Frame
    myFrame.addWindowListener(
      new WindowAdapter(){//anonymous class definition
        public void windowClosing(WindowEvent e){
          System.exit(0);//terminate the program
        }//end windowClosing()
      }//end WindowAdapter
    );//end addWindowListener

        }//end constructor
  //=====================================================//
  
  //This is an inner class of the GUI class used to cause
  // the container referenced by panelToPrint or the Frame
  // referenced by myFrame to be printed.
  class PrintActionListener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      //Get a PrintJob object.  This causes the system-
      // standard print dialog to appear.  Closing the
      // dialog without allowing printing will return null.
      PrintJob myPrintJob = myFrame.getToolkit().
            getPrintJob(
              myFrame, "Copyright 1998 R.G.Baldwin", null);
      if(myPrintJob != null){
        //Get a graphics object for printing
        Graphics printGraphics = myPrintJob.getGraphics();
        if(printGraphics != null){
          //Invoke the printAll() method of the Panel
          // object or the Frame object to cause the 
          // components contained in the Panel or the Frame
          // to be drawn on the graphics object and painted
          // onto the paper in the printer.
          if(e.getActionCommand().equals("Print the Panel"))
            panelToPrint.printAll(printGraphics);
          else myFrame.printAll(printGraphics);

          //Cause a form feed on the printer and free
          // the resources tied up by the graphics object.
          printGraphics.dispose();
        }//end if statement
        else 
          System.out.println(
                       "Didn't get print graphics object");
        //End the print job and do any necessary cleanup.
        myPrintJob.end();
      }//end if statement
      else 
        System.out.println("PrintJob cancelled by user");

    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//
    
  //This is an inner class of the GUI class used to cause
  // panel0 to be selected for display and printing.
  class SelectPanel0Listener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      myFrame.remove(panelToPrint);
      panelToPrint = panel0;
      myFrame.add(panelToPrint,"Center");
      myFrame.invalidate();//force a redraw
//      myFrame.repaint();
      //Note that repaint() can be used here instead of
      // setVisible() if setVisible() has been previously
      // invoked on the Frame containing this panel at
      // some previous time in the program.  I don't know
      // which is most efficient.  If repaint() is most
      // efficient, one possibility would be to cycle 
      // through all the possible panels when the program
      // starts invoking setVisible(true) for each of them
      // and then using repaint() here instead of 
      // setVisible().
      myFrame.setVisible(true);
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

  //This is an inner class of the GUI class used to cause
  // panel1 to be selected for display and printing.
  class SelectPanel1Listener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      myFrame.remove(panelToPrint);
      panelToPrint = panel1;
      myFrame.add(panelToPrint,"Center");
      myFrame.invalidate();//force a redraw
//      myFrame.repaint(); //see comment above
      myFrame.setVisible(true);
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

}//end class GUI
//=======================================================//

Sample Program for Painting on the Paper with AWT

The purpose of this program is to demonstrate the ability to selectively print the contents of the components in an AWT container that is embedded inside another AWT container.

The word selectively is used in this case to differentiate the approach to printing used in this program from the approach used in the program named Print04 as described earlier in this lesson.  That program used the printAll() method to print all of the components in a container.  This program has the ability to select which components are to be printed.  It also has the ability to print selected information about those components.

Similar to the program named Print04, this program places one of two selectable custom Panel objects and three Button objects in a Frame. The Panel objects know how to print themselves when their overridden paint() method is invoked.

One of the buttons has a listener that causes the currently selected Panel to print itself.  This requires that each panel have an overridden paint() method which in turn requires that each panel be a custom Panel type that extends Panel.  The overridden paint() method defines the manner in which the panel prints itself.

The two other buttons are used to select between the two Panel objects for display and printing.  In other words, the user can select between two different panels and cause the one currently installed in the Frame to be printed.

When the selected Panel is printed, the other components in the Frame are ignored.

For purposes of illustration, one of the selectable Panel objects contains a Label, a TextField, and a Button that is not active.

The other selectable Panel contains a Label, a TextField and two Button objects that are not active.

The print format defined in the overridden paint() methods causes the current text from the Label and the TextField to be printed and causes the captions on the Button objects to be printed.  This print format is for illustration only. Using this approach, you have total freedom to decide how to print the information associated with each of the components in your program.

This program was tested using JDK 1.1.6 under Win95

Interesting Code Fragments for Painting on the Paper with AWT

Much of the code in this program is either identical or very similar to the code in the previously discussed program named Print04.  We will not repeat that discussion.  Rather, we will attempt to present and discuss only the code that represents new programming concepts in this section.  A complete listing of the program is provided in a later section.

In some cases, I will provide a skeleton showing //snip to indicate that code has been omitted for brevity.

Consider first the GUI class as shown in the following fragment.

This fragment shows references to two selectable custom panels that can be installed in the Frame object.

Significantly different from the previous program is the fact that  they are of custom panel type MyPanelTypeX.  They cannot be of type Panel as in the previous program because it will later be necessary to provide an overridden paint() method.  Therefore, they must be of a type that extends Panel.  Also, they must be of different types because their appearance is different and the manner in which they print themselves is different.  

class GUI {
  //snip
  MyPanelType0 panel0;
  MyPanelType1 panel1;

The constructor for the GUI class is very similar to the previous program except that the instantiation of the custom panels invokes the constructors for the custom panel classes as shown in the following fragment.

    
  public GUI(){//constructor
    //snip

    panel0 = new MyPanelType0();
    panel1 = new MyPanelType1();

    //snip
  }//end constructor
  //=====================================================//

This brings us to an inner class of the GUI class that is used to cause the custom panel object referenced by the reference variable named areaToPrint to print itself.  This is accomplished by getting a printer context and passing it to the overridden paint() method for the custom panel referenced by areaToPrint.

Most of the code in this class is the same as or very similar to the code in the previous program.  The following fragment highlights the code that is significantly different between the two.

The fragment picks up with the actionPerformed() method of the PrintActionListener class where we invoke the custom paint() method of the object referred to by areaToPrint passing the printGraphics object as a parameter. This will cause the object to print itself.

    public void actionPerformed(ActionEvent e){
      //snip
      if(myPrintJob != null){
        //Get graphics object for printing
        Graphics printGraphics = myPrintJob.getGraphics();
        if(printGraphics != null){
          //Invoke custom paint() method of the 
          // object referred to by areaToPrint passing
          // PrintGraphics object as parameter. This
          // will cause object to print itself.
          areaToPrint.paint(printGraphics);
          //Cause form feed on printer and free
          // resources tied up by graphics object.
          printGraphics.dispose();
        }//end if statement

      //snip
    }//end actionPerformed()

That brings us to the class from which the custom panels are instantiated.  Objects of this class know how to print themselves when their overridden paint() method is invoked and passed a PrintGraphics object as a parameter.  The format in which the material is printed is defined in the overridden paint() method.

Some of the code in this class is pretty standard stuff, so I will snip it out for brevity.

An important point to note is that this class extends the Panel class.  That makes it possible to override the paint() method of the Panel class.

I will preserve the overridden paint() method because it contains information that you need to know.

In the overridden paint() method, it is necessary to separate screen painting from printer painting. Otherwise, this material that is intended for printing would also appear on the screen when the object is painted on the screen.

A test is performed to execute the primary code in the overridden paint method only if the Graphics object is of type PrintGraphics. If not, the default paint method of the superclass is invoked to preserve the ability to paint on the screen.

This overridden version of paint() prints a header line and then simply extracts data from the components in the panel and prints that data on successive lines.  This is where you would insert the code required to print your data in your format.

I will continue this discussion following the box containing the fragment.

  class MyPanelType0 extends Panel{
    //Components containing data to be printed.
    Label panel0Label;
    TextField panel0TextField;
    Button panel0Button0;

    //snip the constructor

    public void paint(Graphics g){
      if(g instanceof PrintGraphics){
        int leftMargin = 10;//X-position of each line
        int topMargin = 20;//Y-position of first line
        int lineIncrement = 13;//height of each line
        g.setFont(new Font("Serif", Font.BOLD, 18));
        
        g.drawString("Hello from Panel 0",leftMargin,
                               topMargin += lineIncrement);
        g.setFont(new Font("Serif", Font.PLAIN, 10));
        g.drawString(
            "Contents of Label: " + panel0Label.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Contents of TextField: " + 
                panel0TextField.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Caption on Button: " + 
                panel0Button0.getLabel(),leftMargin,
                               topMargin += lineIncrement);
      }//end if
      else//g is not a PrintGraphics object
        //Invoke the paint method of the Panel class.
        super.paint(g);
    }//end overridden paint()
  }//end class MyPanelType0
  //=====================================================//

Note that printing contexts do not have a default font. You must set it or the system will crash under Win95 (as of JDK 1.1.6).

As you can see, printing consists simply of invoking the drawString() method on the PrintGraphics object in much the same way that we programmed the Hello World applet way back at the beginning of the Introductory Java Tutorial.

You can think of this simply as painting on the paper.  This means that you  have the ability to place virtually any graphics on the paper that you could place on the screen (circles, lines, boxes, etc.).  Therefore, you don't have to be satisfied with simple text output.  In this respect, you are limited only by your own creativity.

At the end of this overridden paint() method (on the else side of an if-else statement) is a statement that invokes the paint() method of the superclass (Panel in this case) when the overridden paint() method is invoked but it is not invoked with a parameter of type PrintGraphics.  This is needed to preserve the ability to paint the custom panel on the screen.

This class is followed by another very similar class for the other custom panel.  I will omit that class for brevity, but you can view it in the complete program listing that follows later.

This is also followed by two class definitions for action listeners that are used to select the custom panel to be installed in the Frame for viewing and printing.  These class definitions are essentially the same as in the program named Print04.  Therefore, we will also omit them for brevity.

And that concludes the discussion of interesting code fragments for this sample program.

Program Listing for Painting on the Paper with AWT

A complete listing of the program is contained in this section.  One additional sample program follows this one which deals with using the paint method to print Swing components.

/*File Print05.java
Copyright 1998 R.G.Baldwin

The purpose of this program is to demonstrate the ability
to selectively print the contents of the components in an
AWT container that is embedded inside another AWT 
container.

The word selectively is used in this case to differentiate
the approach to printing used in this program from the
approach used in the program named Print04.  That program
used the printAll() method to print all of the components
in a container.  This program has the ability to select
which components are to be printed.  It also has the 
ability to print selected information about those
components.

Similar to the program named Print04, this program places
one of two selectable custom Panel objects and three
Button objects in a Frame. The Panel objects know how to
print themselves when their overridden paint() method is
invoked.

One of the buttons has a listener that causes the currently
selected Panel to print itself.  This requires that each 
panel have an overridden paint() method which in turn 
requires that each panel be a custom panel type that 
extends Panel.  The overridden paint() method defines the 
manner in which the panel prints itself.

The two other buttons are used to select between the two 
Panels for display and printing.  In other words, the user
can select between two different panels and cause the one 
currently installed in the Frame to be printed.

When the selected Panel is printed, the other components in
the Frame are ignored.

For purposes of illustration, one of the selectable Panel
objects contains a Label, a TextField, and a Button that
is not active.

The other selectable Panel contains a Label, a TextField 
and two Button objects that are not active.

The print format defined in the overridden paint() methods
causes the current text from the Label and the TextField to
be printed and causes the labels from the Button objects
to be printed.  This print format is for illustration only.
Using this approach, you have total freedom to decide how
to print the information associated with the components
in your program.

Tested using JDK 1.1.6 under Win95
**********************************************************/

import java.awt.*;
import java.awt.event.*;
//=======================================================//

public class Print05 {
  public static void main(String[] args){
    //instantiate a Graphical User Interface object
    GUI gui = new GUI();
  }//end main
}//end class Print05
//=======================================================//

//This class is used to instantiate a Graphical User
// Interface object
class GUI {
  Frame myFrame = new Frame("Copyright 1997, R.G.Baldwin");
  
  //The container objects referenced by areaToPrint will be
  // asked to print themselves.
  Panel areaToPrint = null;
  
  //Two selectable custom panels that can be installed
  // in the Frame object.  Note that they are of custom
  // panel type MyPanelTypeX.  They must be of different
  // types because their appearance is different and the
  // manner in which they print themselves is different.
  MyPanelType0 panel0;
  MyPanelType1 panel1;
    
  public GUI(){//constructor
    //The following button causes the container object
    // currently referred to by areaToPrint to print 
    // itself.
          Button printButton = new Button("Print");
    printButton.addActionListener(
                                new PrintActionListener());
    myFrame.add(printButton,"North");
    
    //The following buttons are used to select different
    // panels for display and printing.
    Button selectPanel0Button = 
                              new Button("Select Panel 0");
    selectPanel0Button.addActionListener(
                               new SelectPanel0Listener());
    myFrame.add(selectPanel0Button,"West");
    
    Button selectPanel1Button = 
                              new Button("Select Panel 1");
    selectPanel1Button.addActionListener(
                               new SelectPanel1Listener());
    myFrame.add(selectPanel1Button,"East");
    
    //Construct the selectable Panels that will be assigned
    // to the areaToPrint reference when a selection is
    // made.  When these panels print themselves, the print
    // routine causes the contents of the components in the
    // container to be printed.
    panel0 = new MyPanelType0();
    panel1 = new MyPanelType1();

    //Need a valid reference in areaToPrint to prevent a
    // null pointer exception when a selection is made and
    // an attempt is made to remove the old reference.
    areaToPrint = panel0;

    myFrame.setSize(340,200);
    myFrame.setVisible(true);

    //This is an anonymous inner class of the GUI class 
    // used to terminate the program when the user closes
    // the Frame
    myFrame.addWindowListener(
      new WindowAdapter(){//anonymous class definition
        public void windowClosing(WindowEvent e){
          System.exit(0);//terminate the program
        }//end windowClosing()
      }//end WindowAdapter
    );//end addWindowListener
        }//end constructor
  //=====================================================//
  
  //This is an inner class of the GUI class used to cause
  // the container referenced by areaToPrint to print
  // itself.  This is accomplished by getting a printer
  // context and passing it to the overridden paint()
  // method for the container referenced by areaToPrint.
  class PrintActionListener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      //Get a PrintJob object.  This causes the system-
      // standard print dialog to appear.  Closing the
      // dialog without allowing printing will return null.
      PrintJob myPrintJob = myFrame.getToolkit().
                 getPrintJob(
                   myFrame, "Copyright R.G.Baldwin", null);
      if(myPrintJob != null){
        //Get a graphics object for printing
        Graphics printGraphics = myPrintJob.getGraphics();
        if(printGraphics != null){
          //Invoke the custom paint() method of the 
          // object referred to by areaToPrint passing
          // the PrintGraphics object as a parameter. This
          // will cause the object to print itself.
          areaToPrint.paint(printGraphics);
          //Cause a form feed on the printer and free
          // the resources tied up by the graphics object.
          printGraphics.dispose();
        }//end if statement
        else 
          System.out.println(
                       "Didn't get print graphics object");
        //End the print job and do any necessary cleanup.
        myPrintJob.end();
      }//end if statement
      else 
        System.out.println("PrintJob cancelled by user");

    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

  //This is a custom Panel class.  Objects of this class
  // know how to print themselves when their overridden
  // paint() method is called and passed a PrintGraphics
  // object as a parameter.  The format in which the
  // object is printed is defined in the overridden
  // paint() method.
  class MyPanelType0 extends Panel{
    //These are the components in the object that contain
    // data to be printed.
    Label panel0Label;
    TextField panel0TextField;
    Button panel0Button0;
    //---------------------------------------------------//

    //This is the constructor for the custom Panel object
    MyPanelType0(){
      panel0Label = new Label("Panel 0");
      this.add(panel0Label);
      panel0TextField = new TextField("TextField");
      this.add(panel0TextField);
      panel0Button0 = new Button("panel0Button0");
      this.add(panel0Button0);
      this.setBackground(Color.yellow);
    }//end constructor
    //---------------------------------------------------//
    
    //Override paint() here.  Did not attempt to handle
    // fontsize in order to produce pleasing output.
    public void paint(Graphics g){
      //Separate screen painting from printer painting.
      // Only execute the following code if the Graphics
      // object is of type PrintGraphics.  Otherwise, this
      // material would appear on the screen when the 
      // object is painted on the screen.
      if(g instanceof PrintGraphics){
        //This overridden version of paint() prints a
        // header line and then simply extracts data from
        // the components in the panel and prints that
        // data on successive lines.
        int leftMargin = 10;//X-position of each line
        int topMargin = 20;//Y-position of first line
        int lineIncrement = 13;//height of each line

        //Printing contexts do not have a default font. You
        // MUST set it or the system will crash under Win95
        g.setFont(new Font("Serif", Font.BOLD, 18));
        
        g.drawString("Hello from Panel 0",leftMargin,
                               topMargin += lineIncrement);
        g.setFont(new Font("Serif", Font.PLAIN, 10));
        g.drawString(
            "Contents of Label: " + panel0Label.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Contents of TextField: " + 
                panel0TextField.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Caption on Button: " + 
                panel0Button0.getLabel(),leftMargin,
                               topMargin += lineIncrement);
      }//end if
      else//g is not a PrintGraphics object
        //Invoke the paint method of the Panel class.
        super.paint(g);
    }//end overridden paint()
  }//end class MyPanelType0
  //=====================================================//

  //This is a custom Panel class.  Objects of this class
  // know how to print themselves when their overridden
  // paint() method is called and passed a PrintGraphics
  // object as a parameter.  See explanatory comments in
  // the definition of the class named MyPanelType0.
  class MyPanelType1 extends Panel{
    Label panel1Label;
    TextField panel1TextField;
    Button panel1Button0;
    Button panel1Button1;
    //---------------------------------------------------//
    
    MyPanelType1(){//constructor
      panel1Label = new Label("Panel 1");
      this.add(panel1Label);
      panel1TextField = new TextField("TextField");
      this.add(panel1TextField);
      panel1Button0 = new Button("panel1Button0");
      this.add(panel1Button0);
      panel1Button1 = new Button("panel1Button1");
      this.add(panel1Button1);
      this.setBackground(Color.pink);
    }//end constructor
    //---------------------------------------------------//

    //Override paint() here.  Did not attempt to handle
    // fontsize well and produce pleasing output.
    public void paint(Graphics g){
      //Separate screen painting from printer painting
      if(g instanceof PrintGraphics){
        int leftMargin = 10;//X-position of each line
        int topMargin = 20;//Y-position of first line
        int lineIncrement = 13;//height of each line
        
        //Printing contexts do not have a default font. You
        // must set it or the system will crash under Win95
        g.setFont(new Font("Serif", Font.BOLD, 18));
        g.drawString("Hello from Panel 1",leftMargin,
                               topMargin += lineIncrement);
        
        g.setFont(new Font("Serif", Font.PLAIN, 10));
        g.drawString(
            "Contents of Label: " + panel1Label.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Contents of TextField: " + 
                panel1TextField.getText(),leftMargin,
                               topMargin += lineIncrement);
        g.drawString(
            "Caption on Button: " + 
                panel1Button0.getLabel(),leftMargin,
                               topMargin += lineIncrement);
        g.drawString(
            "Caption on Button: " + 
                panel1Button1.getLabel(),leftMargin,
                               topMargin += lineIncrement);
      }//end if
      else//g is not a PrintGraphics object
        super.paint(g);
    }//end overridden paint()
  }//end class MyPanelType1
  //=====================================================//
  
  //This is an inner class of the GUI class used to cause
  // panel0 to be selected for display and printing.
  // Obviously, this and the next class could be combined
  // into a single class that would use the source of the
  // event to determine which panel to display.
  class SelectPanel0Listener implements ActionListener{
    public void actionPerformed(ActionEvent e){
      myFrame.remove(areaToPrint);
      areaToPrint = panel0;
      myFrame.add(areaToPrint,"Center");
      myFrame.invalidate();//force a redraw
      myFrame.setVisible(true);
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

  //This is an inner class of the GUI class used to cause
  // panel1 to be selected for display and printing.
  class SelectPanel1Listener implements ActionListener{
    public void actionPerformed(ActionEvent e){
      myFrame.remove(areaToPrint);
      areaToPrint = panel1;
      myFrame.add(areaToPrint,"Center");
      myFrame.invalidate();//force a redraw
      myFrame.setVisible(true);
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

}//end class GUI
//=======================================================//

Sample Program for Painting on the Paper with Swing

This is a Swing version of the program named Print05.java.

The only significant modifications required to convert Print05 to this Swing version were:

Otherwise, this program is essentially the same as the previous program named Print05 and therefore, no further discussion will be provided.

Program Listing for Painting on the Paper with Swing

This section provides a complete listing of the program.

/*File Print06.java
Copyright 1998 R.G.Baldwin

This is a Swing version of the program named Print05.java.

The only significant modifications required to convert
Print05 to this Swing version was to replace all the AWT
components (such as Button) with Swing components (such
as JButton), and then to apply the getContentPane()
method invocation to all operations that deal with the
layer in the JFrame where the components reside.

The purpose of this program is to demonstrate the ability
to selectively print the contents of Swing components in
a Swing container that is embedded inside another Swing 
container.

The word selectively is used in this case to differentiate
the approach to printing used in this program from the
approach used in the program named Print04.  That program
used the printAll() method to print all of the components
in a container.  This program has the ability to select
which components are to be printed.  It also has the 
ability to print selected information about those
components.

Similar to the program named Print04, this program places
one of two selectable custom JPanel objects and three
JButton objects in a JFrame. The JPanel objects know how to
print themselves when their overridden paint() method is
invoked.

One of the buttons has a listener that causes the currently
selected JPanel to print itself.  This requires that each 
panel have an overridden paint() method which in turn 
requires that each panel be a custom panel type that 
extends JPanel.  The overridden paint() method defines the 
manner in which the panel prints itself.

The two other buttons are used to select between the two 
JPanel objects for display and printing.  In other words,
the user can select between two different panels and cause
the one currently installed in the JFrame to be printed.

When the selected JPanel is printed, the other components in
the JFrame are ignored.

For purposes of illustration, one of the selectable JPanel
objects contains a JLabel, a JTextField, and a JButton that
is not active.

The other selectable JPanel contains a JLabel, a JTextField 
and two JButton objects that are not active.

The print format defined in the overridden paint() methods
causes the current text from the JLabel and the JTextField to
be printed and causes the captions from the JButton objects
to be printed.  This print format is for illustration only.
Using this approach, you have total freedom to decide how
to print the information associated with the components
in your program.

Tested using JDK 1.1.6 and Swing 1.0.1 under Win95
**********************************************************/

import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
//=======================================================//

public class Print06 {
  public static void main(String[] args){
    //instantiate a Graphical User Interface object
    GUI gui = new GUI();
  }//end main
}//end class Print06
//=======================================================//

//This class is used to instantiate a Graphical User
// Interface object
class GUI {
  JFrame myFrame = new JFrame("Copyright 1997, R.G.Baldwin");
  
  //The container objects referenced by areaToPrint will be
  // asked to print themselves.
  JPanel areaToPrint = null;
  
  //Two selectable custom panels that can be installed
  // in the JFrame object.  Note that they are of custom
  // panel type MyPanelTypeX.  They must be of different
  // types because their appearance is different and the
  // manner in which they print themselves is different.
  MyPanelType0 panel0;
  MyPanelType1 panel1;
    
  public GUI(){//constructor
    //The following button causes the container object
    // currently referred to by areaToPrint to print 
    // itself.
          JButton printButton = new JButton("Print");
    printButton.addActionListener(
                                new PrintActionListener());
    myFrame.getContentPane().add(printButton,"North");
    
    //The following buttons are used to select different
    // panels for display and printing.
    JButton selectPanel0Button = 
                            new JButton("Select JPanel 0");
    selectPanel0Button.addActionListener(
                               new SelectPanel0Listener());
    myFrame.getContentPane().add(selectPanel0Button,"West");
    
    JButton selectPanel1Button = 
                            new JButton("Select JPanel 1");
    selectPanel1Button.addActionListener(
                               new SelectPanel1Listener());
    myFrame.getContentPane().add(selectPanel1Button,"East");
    
    //Construct the selectable Panels that will be assigned
    // to the areaToPrint reference when a selection is
    // made.  When these panels print themselves, the print
    // routine causes the contents of the components in the
    // container to be printed.
    panel0 = new MyPanelType0();
    panel1 = new MyPanelType1();

    //Need a valid reference in areaToPrint to prevent a
    // null pointer exception when a selection is made and
    // an attempt is made to remove the old reference.
    areaToPrint = panel0;

    myFrame.setSize(400,200);
    myFrame.setVisible(true);

    //This is an anonymous inner class of the GUI class 
    // used to terminate the program when the user closes
    // the JFrame
    myFrame.addWindowListener(
      new WindowAdapter(){//anonymous class definition
        public void windowClosing(WindowEvent e){
          System.exit(0);//terminate the program
        }//end windowClosing()
      }//end WindowAdapter
    );//end addWindowListener
        }//end constructor
  //=====================================================//
  
  //This is an inner class of the GUI class used to cause
  // the container referenced by areaToPrint to print
  // itself.  This is accomplished by getting a printer
  // context and passing it to the overridden paint()
  // method for the contrainer referenced by areaToPrint.
  class PrintActionListener implements ActionListener{

    public void actionPerformed(ActionEvent e){
      //Get a PrintJob object.  This causes the system-
      // standard print dialog to appear.  Closing the
      // dialog without allowing printing will return null.
      PrintJob myPrintJob = myFrame.getToolkit().
                 getPrintJob(
                   myFrame, "Copyright R.G.Baldwin", null);
      if(myPrintJob != null){
        //Get a graphics object for printing
        Graphics printGraphics = myPrintJob.getGraphics();
        if(printGraphics != null){
          //Invoke the custom paint() method of the 
          // object referred to by areaToPrint passing
          // the PrintGraphics object as a parameter. This
          // will cause the object to print itself.
          areaToPrint.paint(printGraphics);
          //Cause a form feed on the printer and free
          // the resources tied up by the graphics object.
          printGraphics.dispose();
        }//end if statement
        else 
          System.out.println(
                       "Didn't get print graphics object");
        //End the print job and do any necessary cleanup.
        myPrintJob.end();
      }//end if statement
      else 
        System.out.println("PrintJob cancelled by user");

    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

  //This is a custom JPanel class.  Objects of this class
  // know how to print themselves when their overridden
  // paint() method is called and passed a PrintGraphics
  // object as a parameter.  The format in which the
  // object is printed is defined in the overridden
  // paint() method.
  class MyPanelType0 extends JPanel{
    //These are the components in the object that contain
    // data to be printed.
    JLabel panel0Label;
    JTextField panel0TextField;
    JButton panel0Button0;
    //---------------------------------------------------//

    //This is the constructor for the custom JPanel object
    MyPanelType0(){
      panel0Label = new JLabel("JPanel 0");
      this.add(panel0Label);
      panel0TextField = new JTextField("JTextField");
      this.add(panel0TextField);
      panel0Button0 = new JButton("panel0Button0");
      this.add(panel0Button0);
      this.setBackground(Color.yellow);
    }//end constructor
    //---------------------------------------------------//
    
    //Override paint() here.  Did not attempt to handle
    // fontsize in order to produce pleasing output.
    public void paint(Graphics g){
      //Separate screen painting from printer painting.
      // Only execute the following code if the Graphics
      // object is of type PrintGraphics.  Otherwise, this
      // material would appear on the screen when the 
      // object is painted on the screen.
      if(g instanceof PrintGraphics){
        //This overridden version of paint() prints a
        // header line and then simply extracts data from
        // the components in the panel and prints that
        // data on successive lines.
        int leftMargin = 10;//X-position of each line
        int topMargin = 20;//Y-position of first line
        int lineIncrement = 13;//height of each line

        //Printing contexts do not have a default font. You
        // MUST set it or the system will crash under Win95
        g.setFont(new Font("Serif", Font.BOLD, 18));
        
        g.drawString("Hello from JPanel 0",leftMargin,
                               topMargin += lineIncrement);
        g.setFont(new Font("Serif", Font.PLAIN, 10));
        g.drawString(
            "Contents of JLabel: " + panel0Label.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Contents of JTextField: " + 
                panel0TextField.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Caption on JButton: " + 
                panel0Button0.getText(),leftMargin,
                               topMargin += lineIncrement);
      }//end if
      else//g is not a PrintGraphics object
        //Invoke the paint method of the JPanel class.
        super.paint(g);
    }//end overridden paint()
  }//end class MyPanelType0
  //=====================================================//

  //This is a custom JPanel class.  Objects of this class
  // know how to print themselves when their overridden
  // paint() method is called and passed a PrintGraphics
  // object as a parameter.  See explanatory comments in
  // the definition of the class named MyPanelType0.
  class MyPanelType1 extends JPanel{
    JLabel panel1Label;
    JTextField panel1TextField;
    JButton panel1Button0;
    JButton panel1Button1;
    //---------------------------------------------------//
    
    MyPanelType1(){//constructor
      panel1Label = new JLabel("JPanel 1");
      this.add(panel1Label);
      panel1TextField = new JTextField("JTextField");
      this.add(panel1TextField);
      panel1Button0 = new JButton("panel1Button0");
      this.add(panel1Button0);
      panel1Button1 = new JButton("panel1Button1");
      this.add(panel1Button1);
      this.setBackground(Color.pink);
    }//end constructor
    //---------------------------------------------------//

    //Override paint() here.  Did not attempt to handle
    // fontsize well and produce pleasing output.
    public void paint(Graphics g){
      //Separate screen painting from printer painting
      if(g instanceof PrintGraphics){
        int leftMargin = 10;//X-position of each line
        int topMargin = 20;//Y-position of first line
        int lineIncrement = 13;//height of each line
        
        //Printing contexts do not have a default font. You
        // must set it or the system will crash under Win95
        g.setFont(new Font("Serif", Font.BOLD, 18));
        g.drawString("Hello from JPanel 1",leftMargin,
                               topMargin += lineIncrement);
        
        g.setFont(new Font("Serif", Font.PLAIN, 10));
        g.drawString(
            "Contents of JLabel: " + panel1Label.getText(),
                    leftMargin,topMargin += lineIncrement);
        g.drawString(
            "Contents of JTextField: " + 
                panel1TextField.getText(),leftMargin,
                               topMargin += lineIncrement);
        g.drawString(
            "Caption on JButton: " + 
                panel1Button0.getText(),leftMargin,
                               topMargin += lineIncrement);
        g.drawString(
            "Caption on JButton: " + 
                panel1Button1.getText(),leftMargin,
                               topMargin += lineIncrement);
      }//end if
      else//g is not a PrintGraphics object
        super.paint(g);
    }//end overridden paint()
  }//end class MyPanelType1
  //=====================================================//
  
  //This is an inner class of the GUI class used to cause
  // panel0 to be selected for display and printing.
  // Obviously, this and the next class could be combined
  // into a single class that would use the source of the
  // event to determine which panel to display.
  class SelectPanel0Listener implements ActionListener{
    public void actionPerformed(ActionEvent e){
      myFrame.getContentPane().remove(areaToPrint);
      areaToPrint = panel0;
      myFrame.getContentPane().add(areaToPrint,"Center");
      myFrame.getContentPane().invalidate();
      myFrame.setVisible(true);
      myFrame.repaint();
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

  //This is an inner class of the GUI class used to cause
  // panel1 to be selected for display and printing.
  class SelectPanel1Listener implements ActionListener{
    public void actionPerformed(ActionEvent e){
      myFrame.getContentPane().remove(areaToPrint);
      areaToPrint = panel1;
      myFrame.getContentPane().add(areaToPrint,"Center");
      myFrame.getContentPane().invalidate();
      myFrame.setVisible(true);
      myFrame.repaint();
    }//end actionPerformed()
  }//end class PrintActionListener
  //=====================================================//

}//end class GUI
//=======================================================//

-end-