JTable Druckfunktion anpassen: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
K
 
(3 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
 
Seit Java 1.5 wird das Drucken der JTable unterstützt.
 
Seit Java 1.5 wird das Drucken der JTable unterstützt.
  
'''1. Die standard Druckfunktion'''
+
== [http://download.oracle.com/javase/6/docs/api/javax/swing/JTable.html#print%28%29 '''1. Die standard Druckfunktion'''] ==
  
 
print()
 
print()
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTable.html#print()
 
  
 
print(JTable.PrintMode)
 
print(JTable.PrintMode)
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTable.html#print(javax.swing.JTable.PrintMode)
 
  
 
print(JTable.PrintMode, MessageFormat, MessageFormat)
 
print(JTable.PrintMode, MessageFormat, MessageFormat)
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTable.html#print(javax.swing.JTable.PrintMode,%20java.text.MessageFormat,%20java.text.MessageFormat)
 
  
 
print(JTable.PrintMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean)
 
print(JTable.PrintMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean)
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTable.html#print(javax.swing.JTable.PrintMode,%20java.text.MessageFormat,%20java.text.MessageFormat,%20boolean,%20javax.print.attribute.PrintRequestAttributeSet,%20boolean)
 
  
JTable.PrintMode.NORMAL druckt die JTable mit der aktuellen Grösse.
+
'''print(JTable.PrintMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean, PrintService)''' (seit 1.6)
JTable.PrintMode.FIT_WIDTH verkleinert die JTable, wenn nötig, so daß alle Spalten auf eine Seite passen.
+
 
Header und Footer Text kann hinzugefügt werden (ansonsten einfach null angeben);
+
 
 +
'''JTable.PrintMode.NORMAL''' druckt die JTable mit der aktuellen Grösse.
 +
'''JTable.PrintMode.FIT_WIDTH''' verkleinert die JTable, wenn nötig, so daß alle Spalten auf eine Seite passen.
 +
 
 +
'''Header und Footer Text''' kann hinzugefügt werden (ansonsten einfach null angeben);
 
im MessageFormat kann man als ArgumentIndex 0 für die Seitennummer angegeben:
 
im MessageFormat kann man als ArgumentIndex 0 für die Seitennummer angegeben:
Code:
+
<syntaxhighlight lang="java">
 +
new MessageFormat("Page {0}")
 +
</syntaxhighlight>
 +
 
 +
Mit dem '''ersten boolean''' Parameter kann man angeben ob der '''Druckdialog''' angezeigt werden soll oder nicht.
 +
 
 +
'''PrintRequestAttributeSet''' ermöglicht die direkte Angabe von Druckattributen.
  
new MessageFormat("Page {0}")
+
Wenn der '''zweite boolean''' true ist (empfohlen), wird während des Druckvorgangs
 +
ein modaler '''Progressdialog''' angezeigt, mit Abbruchmöglichkeit.
  
Mit dem ersten boolean Parameter kann man angeben ob der Druckdialog angezeigt werden soll oder nicht.
+
'''Printservice''' (seit 1.6) ist der PrintService der zum Drucken benutzt werden soll,  
"PrintRequestAttributeSet" ermöglicht die direkte Angabe von Druckattributen.
+
oder '''null''' zum Drucken auf den Standarddrucker.
Wenn der zweite boolean true ist (empfohlen), wird während des Druckvorgangs
 
ein modaler Progressdialog angezeigt, mit Abbruchmöglichkeit.
 
  
  
'''2. Das Anpassen der Druckfunktion'''
+
== '''2. Das Anpassen der Druckfunktion''' ==
  
 
Folgende Methode ist verfügbar für erweiterte Druckanforderungen:
 
Folgende Methode ist verfügbar für erweiterte Druckanforderungen:
  
getPrintable(JTable.PrintMode, MessageFormat, MessageFormat)
+
'''getPrintable(JTable.PrintMode, MessageFormat, MessageFormat)'''
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTable.html#getPrintable(javax.swing.JTable.PrintMode,%20java.text.MessageFormat,%20java.text.MessageFormat)
 
  
 
Unten ist ein Demoprogramm das zeigt, wie man die JTable Druckfunktion anpassen kann.
 
Unten ist ein Demoprogramm das zeigt, wie man die JTable Druckfunktion anpassen kann.
 
Als Beispiel drucken wir einen Reportheader mit zwei Zeilen und Rand.
 
Als Beispiel drucken wir einen Reportheader mit zwei Zeilen und Rand.
  
'''3. Das Tutorial von Sun'''
+
== '''3. Das Tutorial von Sun''' ==
  
Ein sehr gutes Tutorial über das Drucken von Tabellen, mit weiteren Einzelheiten: How to Print Tables
+
Ein sehr gutes Tutorial über das Drucken von Tabellen, mit weiteren Einzelheiten: [http://download.oracle.com/javase/tutorial/uiswing/misc/printtable.html How to Print Tables]
http://java.sun.com/docs/books/tutorial/uiswing/misc/printtable.html
+
 
 +
== '''4. Demoprogramm das zeigt, wie man die JTable Druckfunktion anpassen kann''' ==
  
 
[[Datei:TableReportDemo1.jpg]]
 
[[Datei:TableReportDemo1.jpg]]
  
<code=java>/*
+
 
  * TableReportDemo.java
+
Das Druckbild sieht dann etwa so aus (zwei Seiten):
* This demo shows you how to customize the JTable print function.
+
 
  * As an example, we print a report header with two rows and a border.
+
[[Datei:TableReportDemo2.jpg]]
 +
 
 +
 
 +
<syntaxhighlight lang="java">
 +
/*
 +
  * TableReportDemo.java This demo shows you how to customize the JTable print
 +
  * function. As an example, we print a report header with two rows and a border.
 
  */
 
  */
 
import java.awt.*;
 
import java.awt.*;
import java.awt.event.*;
+
import java.awt.event.ActionEvent;
 
import java.awt.print.*;
 
import java.awt.print.*;
import java.util.logging.*;
+
import java.util.logging.Level;
import javax.print.attribute.*;
+
import java.util.logging.Logger;
 +
import javax.print.attribute.HashPrintRequestAttributeSet;
 +
import javax.print.attribute.Size2DSyntax;
 +
import javax.print.attribute.standard.MediaPrintableArea;
 +
import javax.print.attribute.standard.MediaSize;
 +
import javax.print.attribute.standard.MediaSizeName;
 +
import javax.print.attribute.standard.OrientationRequested;
 
import javax.swing.*;
 
import javax.swing.*;
import javax.swing.JTable.*;
+
import javax.swing.table.DefaultTableModel;
import javax.swing.table.*;
+
 
public class TableReportDemo extends JFrame {
+
public final class TableReportDemo extends JFrame
    private JTable table;
+
{
    private JButton btPrint;
+
 
    private Action printAction = new AbstractAction("Print...") {
+
  private JTable table;
        public void actionPerformed(final ActionEvent e) {
+
  private JButton btPrint;
            try {
+
  private Action printAction = new AbstractAction("Print...")
                printJTable();
+
  {
            } catch (PrinterException ex) {
+
 
                Logger.getLogger(TableReportDemo.class.getName()).log(Level.SEVERE, null, ex);
+
      @Override
 +
      public void actionPerformed(final ActionEvent e)
 +
      {
 +
        try
 +
        {
 +
            print(table, new Insets(15, 15, 15, 15), true);
 +
        } catch (PrinterException ex)
 +
        {
 +
            Logger.getLogger(TableReportDemo.class.getName()).log(Level.SEVERE, null, ex);
 +
        }
 +
      }
 +
  };
 +
  private HashPrintRequestAttributeSet attr;
 +
 
 +
  public TableReportDemo()
 +
  {
 +
      super("TableReportDemo");
 +
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +
      btPrint = new JButton();
 +
      add(btPrint, BorderLayout.SOUTH);
 +
      btPrint.setAction(printAction);
 +
      add(new JScrollPane(createTable()), BorderLayout.CENTER);
 +
      pack();
 +
  }
 +
 
 +
  public JTable createTable()
 +
  {
 +
      String[] title = new String[]
 +
      {
 +
        "Title A", "Title B", "Title C", "Title D", "Title E", "Title F", "Title G", "Title H", "Title I"
 +
      };
 +
      String[][] data = new String[][]
 +
      {
 +
      };
 +
      DefaultTableModel model = new DefaultTableModel(data, title);
 +
      table = new JTable(model);
 +
      table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 +
      for (int i = 0; i < 50; i++)
 +
      {
 +
        model.addRow(new String[]
 +
                {
 +
                    String.valueOf(i), "", "", "", "", "", "", "", ""
 +
                });
 +
      }
 +
      return table;
 +
  }
 +
 
 +
  private void print(final JTable table, final Insets insets, final boolean portrait) throws PrinterException
 +
  {
 +
      try
 +
      {
 +
        Printable printable = new TableReport(table);
 +
        PrinterJob job = PrinterJob.getPrinterJob();
 +
        job.setPrintable(printable);
 +
        // create an attribute set to store attributes from the print dialog
 +
        if (attr == null)
 +
        {
 +
            attr = new HashPrintRequestAttributeSet();
 +
            float leftMargin = insets.left;
 +
            float rightMargin = insets.right;
 +
            float topMargin = insets.top;
 +
            float bottomMargin = insets.bottom;
 +
            if (portrait)
 +
            {
 +
              attr.add(OrientationRequested.PORTRAIT);
 
             }
 
             }
        }
+
            else
    };
+
            {
    public TableReportDemo() {
+
              attr.add(OrientationRequested.LANDSCAPE);
        super("TableReportDemo");
+
              leftMargin = insets.top;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
              rightMargin = insets.bottom;
        btPrint = new JButton();
+
              topMargin = insets.right;
        add(btPrint, BorderLayout.SOUTH);
+
              bottomMargin = insets.left;
        btPrint.setAction(printAction);
+
            }
        add(new JScrollPane(createTable()), BorderLayout.CENTER);
+
            attr.add(MediaSizeName.ISO_A4);
        pack();
+
            MediaSize mediaSize = MediaSize.ISO.A4;
    }
+
            float mediaWidth = mediaSize.getX(Size2DSyntax.MM);
    public JTable createTable() {
+
            float mediaHeight = mediaSize.getY(Size2DSyntax.MM);
        String[] title = new String[]{"Title A", "Title B", "Title C", "Title D", "Title E"};
+
            attr.add(new MediaPrintableArea(
        String[][] data = new String[][]{};
+
                    leftMargin, topMargin,
        DefaultTableModel model = new DefaultTableModel(data, title);
+
                    (mediaWidth - leftMargin - rightMargin),
        table = new JTable(model);
+
                    (mediaHeight - topMargin - bottomMargin), Size2DSyntax.MM));
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+
        }            // display a print dialog and record whether or not the user cancels it
        for (int i = 0; i < 50; i++) {
+
        boolean printAccepted = job.printDialog(attr);
             model.addRow(new String[]{String.valueOf(i), "", "", ""});
+
        if (printAccepted)
        }
+
        {// if the user didn't cancel the dialog
        return table;
+
             job.print(attr);// do the printing
    }
+
        }
 +
      } finally
 +
      {
 +
        // possibly restore the original table state here
 +
      }
 +
  }
  
    private void printJTable() throws PrinterException {
+
  public static void main(final String[] args)
        // possibly prepare the table for printing here first
+
  {
        // wrap in a try/finally so table can be restored even if something fails
+
      Runnable gui = new Runnable()
        try {
+
      {
            // fetch the printable
 
            Printable printable = new TableReport(table);
 
            PrinterJob job = PrinterJob.getPrinterJob();// fetch a PrinterJob
 
            job.setPrintable(printable);// set the Printable on the PrinterJob
 
            // create an attribute set to store attributes from the print dialog
 
            PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
 
            // display a print dialog and record whether or not the user cancels it
 
            boolean printAccepted = job.printDialog(attr);
 
            if (printAccepted) {// if the user didn't cancel the dialog
 
                job.print(attr);// do the printing
 
            }
 
        } finally {
 
            // possibly restore the original table state here
 
        }
 
    }
 
    public static void main(final String[] args) {
 
        Runnable gui = new Runnable() {
 
  
            @Override
+
        @Override
            public void run() {
+
        public void run()
                try {
+
        {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+
            try
                } catch (Exception ex) {
+
            {
                    ex.printStackTrace();
+
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                }
+
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
                new TableReportDemo().setVisible(true);
+
            {
 +
              Logger.getLogger("log").log(Level.OFF, ex.getMessage());
 
             }
 
             }
        };
+
            new TableReportDemo().setVisible(true);
        //GUI must start on EventDispatchThread:
+
        }
        SwingUtilities.invokeLater(gui);
+
      };
    }
+
      //GUI must start on EventDispatchThread:
 +
      SwingUtilities.invokeLater(gui);
 +
  }
 
}
 
}
class TableReport implements Printable {
 
    private Printable tablePrintable;
 
    private PageFormat pageFormatJTable;
 
    public TableReport(final JTable table) {
 
        tablePrintable = table.getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
 
    }
 
    public int print(final Graphics graphics, final PageFormat pageFormat,
 
            final int pageIndex) throws PrinterException {
 
        Graphics2D g = (Graphics2D) graphics;
 
        int x1 = (int) pageFormat.getImageableX();
 
        int y1 = (int) pageFormat.getImageableY();
 
        int w1 = (int) pageFormat.getImageableWidth();
 
        int h1 = (int) pageFormat.getImageableHeight();
 
        if (pageFormatJTable == null) {
 
            pageFormatJTable = (PageFormat) pageFormat.clone();
 
            Paper paperJTable = pageFormatJTable.getPaper();
 
            if(pageFormatJTable.getOrientation() == PageFormat.PORTRAIT){
 
                paperJTable.setImageableArea(x1, y1 + 60,//skip header area
 
                        w1, h1 - 90);//reserve space for header and footer
 
            }else{
 
                paperJTable.setImageableArea(y1 + 60, x1,//skip header area
 
                        h1 - 90, w1);//reserve space for header and footer
 
            }
 
            pageFormatJTable.setPaper(paperJTable);
 
        }
 
        String title = "Title";
 
        String subtitle = "Subtitle";
 
        Font f = g.getFont();
 
        g.setFont(g.getFont().deriveFont(15f));
 
        FontMetrics fm = g.getFontMetrics();
 
        g.drawString(title, x1 + (w1-fm.stringWidth(title))/2, y1 + 15);
 
        g.setFont(f);
 
        fm = g.getFontMetrics();
 
        g.drawString(subtitle, x1 + (w1-fm.stringWidth(subtitle))/2, y1 + 30);
 
        g.drawRect(x1, y1, w1, 40);
 
        String footer = "Page " + (pageIndex + 1);
 
        g.drawString(footer, x1 + (w1-fm.stringWidth(footer))/2, y1 + h1 - 10);
 
        //print the table:
 
        Graphics gCopy = g.create();
 
        int retVal = tablePrintable.print(gCopy, pageFormatJTable, pageIndex);
 
        gCopy.dispose();
 
        //
 
        return retVal;
 
    }
 
}</code=java>
 
  
Das Druckbild sieht dann etwa so aus (zwei Seiten):  
+
class TableReport implements Printable
 +
{
 +
 
 +
  private Printable tablePrintable;
 +
  private PageFormat pageFormatJTable;
 +
 
 +
  TableReport(final JTable table)
 +
  {
 +
      tablePrintable = table.getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
 +
  }
 +
 
 +
  @Override
 +
  public int print(final Graphics graphics, final PageFormat pageFormat,
 +
          final int pageIndex) throws PrinterException
 +
  {
 +
      Graphics2D g = (Graphics2D) graphics;
 +
      int x1 = (int) pageFormat.getImageableX();
 +
      int y1 = (int) pageFormat.getImageableY();
 +
      int w1 = (int) pageFormat.getImageableWidth();
 +
      int h1 = (int) pageFormat.getImageableHeight();
 +
      if (pageFormatJTable == null)
 +
      {
 +
        pageFormatJTable = (PageFormat) pageFormat.clone();
 +
        Paper paperJTable = pageFormatJTable.getPaper();
 +
        if (pageFormatJTable.getOrientation() == PageFormat.PORTRAIT)
 +
        {
 +
            paperJTable.setImageableArea(x1, y1 + 60,//skip header area
 +
                    w1, h1 - 90);//reserve space for header and footer
 +
        }
 +
        else
 +
        {
 +
            paperJTable.setImageableArea(y1 + 60, x1,//skip header area
 +
                    h1 - 90, w1);//reserve space for header and footer
 +
        }
 +
        pageFormatJTable.setPaper(paperJTable);
 +
      }
 +
      String title = "Title";
 +
      String subtitle = "Subtitle";
 +
      Font f = g.getFont();
 +
      g.setFont(g.getFont().deriveFont(15f));
 +
      FontMetrics fm = g.getFontMetrics();
 +
      g.drawString(title, x1 + (w1 - fm.stringWidth(title)) / 2, y1 + 15);
 +
      g.setFont(f);
 +
      fm = g.getFontMetrics();
 +
      g.drawString(subtitle, x1 + (w1 - fm.stringWidth(subtitle)) / 2, y1 + 30);
 +
      g.drawRect(x1, y1, w1, 40);
 +
      String footer = "Page " + (pageIndex + 1);
 +
      g.drawString(footer, x1 + (w1 - fm.stringWidth(footer)) / 2, y1 + h1 - 10);
 +
      //print the table:
 +
      Graphics gCopy = g.create();
 +
      int retVal = tablePrintable.print(gCopy, pageFormatJTable, pageIndex);
 +
      gCopy.dispose();
 +
      //
 +
      return retVal;
 +
  }
 +
}
  
[[Datei:TableReportDemo2.jpg]]
+
</syntaxhighlight>
  
[[Kategorie:Java]]
 
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Swing]]
 
[[Kategorie:Swing]]
 
[[Kategorie:Java-Codeschnipsel]]
 
[[Kategorie:Java-Codeschnipsel]]
 +
[[Kategorie:JTable]]

Aktuelle Version vom 28. März 2018, 09:32 Uhr

Seit Java 1.5 wird das Drucken der JTable unterstützt.

1. Die standard Druckfunktion

print()

print(JTable.PrintMode)

print(JTable.PrintMode, MessageFormat, MessageFormat)

print(JTable.PrintMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean)

print(JTable.PrintMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean, PrintService) (seit 1.6)


JTable.PrintMode.NORMAL druckt die JTable mit der aktuellen Grösse. JTable.PrintMode.FIT_WIDTH verkleinert die JTable, wenn nötig, so daß alle Spalten auf eine Seite passen.

Header und Footer Text kann hinzugefügt werden (ansonsten einfach null angeben); im MessageFormat kann man als ArgumentIndex 0 für die Seitennummer angegeben:

new MessageFormat("Page {0}")

Mit dem ersten boolean Parameter kann man angeben ob der Druckdialog angezeigt werden soll oder nicht.

PrintRequestAttributeSet ermöglicht die direkte Angabe von Druckattributen.

Wenn der zweite boolean true ist (empfohlen), wird während des Druckvorgangs ein modaler Progressdialog angezeigt, mit Abbruchmöglichkeit.

Printservice (seit 1.6) ist der PrintService der zum Drucken benutzt werden soll, oder null zum Drucken auf den Standarddrucker.


2. Das Anpassen der Druckfunktion

Folgende Methode ist verfügbar für erweiterte Druckanforderungen:

getPrintable(JTable.PrintMode, MessageFormat, MessageFormat)

Unten ist ein Demoprogramm das zeigt, wie man die JTable Druckfunktion anpassen kann. Als Beispiel drucken wir einen Reportheader mit zwei Zeilen und Rand.

3. Das Tutorial von Sun

Ein sehr gutes Tutorial über das Drucken von Tabellen, mit weiteren Einzelheiten: How to Print Tables

4. Demoprogramm das zeigt, wie man die JTable Druckfunktion anpassen kann

TableReportDemo1.jpg


Das Druckbild sieht dann etwa so aus (zwei Seiten):

TableReportDemo2.jpg


/*
 * TableReportDemo.java This demo shows you how to customize the JTable print
 * function. As an example, we print a report header with two rows and a border.
 */
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.print.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.Size2DSyntax;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public final class TableReportDemo extends JFrame
{

   private JTable table;
   private JButton btPrint;
   private Action printAction = new AbstractAction("Print...")
   {

      @Override
      public void actionPerformed(final ActionEvent e)
      {
         try
         {
            print(table, new Insets(15, 15, 15, 15), true);
         } catch (PrinterException ex)
         {
            Logger.getLogger(TableReportDemo.class.getName()).log(Level.SEVERE, null, ex);
         }
      }
   };
   private HashPrintRequestAttributeSet attr;

   public TableReportDemo()
   {
      super("TableReportDemo");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      btPrint = new JButton();
      add(btPrint, BorderLayout.SOUTH);
      btPrint.setAction(printAction);
      add(new JScrollPane(createTable()), BorderLayout.CENTER);
      pack();
   }

   public JTable createTable()
   {
      String[] title = new String[]
      {
         "Title A", "Title B", "Title C", "Title D", "Title E", "Title F", "Title G", "Title H", "Title I"
      };
      String[][] data = new String[][]
      {
      };
      DefaultTableModel model = new DefaultTableModel(data, title);
      table = new JTable(model);
      table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
      for (int i = 0; i < 50; i++)
      {
         model.addRow(new String[]
                 {
                    String.valueOf(i), "", "", "", "", "", "", "", ""
                 });
      }
      return table;
   }

   private void print(final JTable table, final Insets insets, final boolean portrait) throws PrinterException
   {
      try
      {
         Printable printable = new TableReport(table);
         PrinterJob job = PrinterJob.getPrinterJob();
         job.setPrintable(printable);
         // create an attribute set to store attributes from the print dialog
         if (attr == null)
         {
            attr = new HashPrintRequestAttributeSet();
            float leftMargin = insets.left;
            float rightMargin = insets.right;
            float topMargin = insets.top;
            float bottomMargin = insets.bottom;
            if (portrait)
            {
               attr.add(OrientationRequested.PORTRAIT);
            }
            else
            {
               attr.add(OrientationRequested.LANDSCAPE);
               leftMargin = insets.top;
               rightMargin = insets.bottom;
               topMargin = insets.right;
               bottomMargin = insets.left;
            }
            attr.add(MediaSizeName.ISO_A4);
            MediaSize mediaSize = MediaSize.ISO.A4;
            float mediaWidth = mediaSize.getX(Size2DSyntax.MM);
            float mediaHeight = mediaSize.getY(Size2DSyntax.MM);
            attr.add(new MediaPrintableArea(
                    leftMargin, topMargin,
                    (mediaWidth - leftMargin - rightMargin),
                    (mediaHeight - topMargin - bottomMargin), Size2DSyntax.MM));
         }            // display a print dialog and record whether or not the user cancels it
         boolean printAccepted = job.printDialog(attr);
         if (printAccepted)
         {// if the user didn't cancel the dialog
            job.print(attr);// do the printing
         }
      } finally
      {
         // possibly restore the original table state here
      }
   }

   public static void main(final String[] args)
   {
      Runnable gui = new Runnable()
      {

         @Override
         public void run()
         {
            try
            {
               UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
            {
               Logger.getLogger("log").log(Level.OFF, ex.getMessage());
            }
            new TableReportDemo().setVisible(true);
         }
      };
      //GUI must start on EventDispatchThread:
      SwingUtilities.invokeLater(gui);
   }
}

class TableReport implements Printable
{

   private Printable tablePrintable;
   private PageFormat pageFormatJTable;

   TableReport(final JTable table)
   {
      tablePrintable = table.getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
   }

   @Override
   public int print(final Graphics graphics, final PageFormat pageFormat,
           final int pageIndex) throws PrinterException
   {
      Graphics2D g = (Graphics2D) graphics;
      int x1 = (int) pageFormat.getImageableX();
      int y1 = (int) pageFormat.getImageableY();
      int w1 = (int) pageFormat.getImageableWidth();
      int h1 = (int) pageFormat.getImageableHeight();
      if (pageFormatJTable == null)
      {
         pageFormatJTable = (PageFormat) pageFormat.clone();
         Paper paperJTable = pageFormatJTable.getPaper();
         if (pageFormatJTable.getOrientation() == PageFormat.PORTRAIT)
         {
            paperJTable.setImageableArea(x1, y1 + 60,//skip header area
                    w1, h1 - 90);//reserve space for header and footer
         }
         else
         {
            paperJTable.setImageableArea(y1 + 60, x1,//skip header area
                    h1 - 90, w1);//reserve space for header and footer
         }
         pageFormatJTable.setPaper(paperJTable);
      }
      String title = "Title";
      String subtitle = "Subtitle";
      Font f = g.getFont();
      g.setFont(g.getFont().deriveFont(15f));
      FontMetrics fm = g.getFontMetrics();
      g.drawString(title, x1 + (w1 - fm.stringWidth(title)) / 2, y1 + 15);
      g.setFont(f);
      fm = g.getFontMetrics();
      g.drawString(subtitle, x1 + (w1 - fm.stringWidth(subtitle)) / 2, y1 + 30);
      g.drawRect(x1, y1, w1, 40);
      String footer = "Page " + (pageIndex + 1);
      g.drawString(footer, x1 + (w1 - fm.stringWidth(footer)) / 2, y1 + h1 - 10);
      //print the table:
      Graphics gCopy = g.create();
      int retVal = tablePrintable.print(gCopy, pageFormatJTable, pageIndex);
      gCopy.dispose();
      //
      return retVal;
   }
}