0

I'm a junior Java developer and I want to build a class that takes a JTable and previews on screen how it will be printed on the default printer. This is what we use to call as "Print Preview", just like MS Word, Excel, etc.

As we already know Java does not support this functionality out-of-the-box.

Based on some examples I've found googling I built two classes. The first one TestPreview.java justs shows the JTable and the second one PrintPreview.java previews how the JTable will be printed on the printer.

I have two buttons to go through the pages, "PREV" and "NEXT" and "Print' button to print the JTable. My problem is that when my JTable has too many rows and spans in more than one page PrintPreview does not work. It shows the same page again and again. Also, it does not show the entire JTable data, but only some of them and I can't figure out why.

Please help.

Below is my two classes

TestPreview.java

package printpreviewdemo;

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.print.*;
import java.text.MessageFormat;
import javax.print.attribute.*;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.Sides;
import javax.swing.JTable.PrintMode;

class TestPreview extends JFrame implements ActionListener {
    PrinterJob printerJob = PrinterJob.getPrinterJob();
    HashPrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
    JTable table = null;

    public TestPreview() {
        super("Test of Print Preview");
        getContentPane().add(createTable());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setExtendedState(Frame.MAXIMIZED_BOTH);
        setVisible(true);
    }

    private JPanel createTable() {
       String val[][] = {
            {"A", "Test 01", "A", "Test 01"}, 
            {"B", "Test 02", "B", "Test 02"}, 
            {"C", "Test 03", "C", "Test 03"},
            {"D", "Test 04", "D", "Test 04"}, 
            {"E", "Test 05", "E", "Test 05"}, 
            {"F", "Test 06", "F", "Test 06"},
            {"G", "Test 01", "G", "Test 01"}, 
            {"H", "Test 02", "H", "Test 02"}, 
            {"I", "Test 03", "I", "Test 03"},
            {"J", "Test 03", "J", "Test 03"},
            {"K", "Test 04", "K", "Test 04"}, 
            {"L", "Test 05", "L", "Test 05"}, 
            {"M", "Test 06", "M", "Test 06"},
            {"N", "Test 01", "N", "Test 01"}, 
            {"O", "Test 02", "O", "Test 02"}, 
            {"P", "Test 03", "P", "Test 03"},
            {"Q", "Test 04", "Q", "Test 04"}, 
            {"R", "Test 05", "R", "Test 05"}, 
            {"S", "Test 06", "S", "Test 06"},
            {"T", "Test 01", "T", "Test 01"}, 
            {"U", "Test 02", "U", "Test 02"}, 
            {"V", "Test 03", "V", "Test 03"},
            {"W", "Test 04", "W", "Test 04"}, 
            {"X", "Test 05", "X", "Test 05"}, 
            {"Y", "Test 06", "Y", "Test 06"},
            {"Z", "Test 01", "Z", "Test 01"},
            {"1", "Test 02", "1", "Test 02"}, 
            {"2", "Test 03", "2", "Test 03"},
            {"3", "Test 04", "3", "Test 04"}, 
            {"4", "Test 05", "4", "Test 05"}, 
            {"5", "Test 06", "5", "Test 06"},
            {"6", "Test 01", "6", "Test 01"}, 
            {"7", "Test 02", "7", "Test 02"}, 
            {"8", "Test 03", "8", "Test 03"},
            {"9", "Test 04", "9", "Test 04"}, 
            {"10", "Test 05","10", "Test 05"},
            {"11", "Test 02","11", "Test 02"}, 
            {"12", "Test 03","12", "Test 03"},
            {"13", "Test 04","13", "Test 04"}, 
            {"14", "Test 05","14", "Test 05"}, 
            {"15", "Test 06","15", "Test 06"},
            {"16", "Test 01","16", "Test 01"}, 
            {"17", "Test 02","17", "Test 02"}, 
            {"18", "Test 03","18", "Test 03"},
            {"19", "Test 04","19", "Test 04"}, 
            {"20", "Test 05","20", "Test 05"},
            {"30", "Test 05","30", "Test 05"},
            {"31", "Test 02","31", "Test 02"}, 
            {"32", "Test 03","32", "Test 03"},
            {"33", "Test 04","33", "Test 04"}, 
            {"34", "Test 05","34", "Test 05"}, 
            {"35", "Test 06","35", "Test 06"},
            {"36", "Test 01","36", "Test 01"}, 
            {"37", "Test 02","37", "Test 02"}, 
            {"38", "Test 03","38", "Test 03"},
            {"39", "Test 04","39", "Test 04"}, 
            {"40", "Test 05","40", "Test 05"},
            {"40", "Test 05","40", "Test 05"},
            {"41", "Test 02","41", "Test 02"}, 
            {"42", "Test 03","42", "Test 03"},
            {"43", "Test 04","43", "Test 04"}, 
            {"44", "Test 05","44", "Test 05"}, 
            {"45", "Test 06","45", "Test 06"},
            {"46", "Test 01","46", "Test 01"}, 
            {"47", "Test 02","47", "Test 02"}, 
            {"48", "Test 03","48", "Test 03"},
            {"49", "Test 04","49", "Test 04"}, 
            {"50", "Test 05","50", "Test 05"},
            {"50", "Test 05","50", "Test 05"},
            {"51", "Test 02","51", "Test 02"}, 
            {"52", "Test 03","52", "Test 03"},
            {"53", "Test 04","53", "Test 04"}, 
            {"54", "Test 05","54", "Test 05"}, 
            {"55", "Test 06","55", "Test 06"},
            {"56", "Test 01","56", "Test 01"}, 
            {"57", "Test 02","57", "Test 02"}, 
            {"58", "Test 03","58", "Test 03"},
            {"59", "Test 04","59", "Test 04"}, 
            {"60", "Test 05","60", "Test 05"}
        };

        String headers[] = {"A", "B", "C", "D"};
        table = new JTable(val, headers);
        JButton previewButton = new JButton("Preview Table");
        previewButton.addActionListener(this);
        JPanel panel = new JPanel(new BorderLayout()), top = new JPanel(new FlowLayout());
        top.add(previewButton);
        panel.add(top, "North"); 
        panel.add(new JScrollPane(table), "Center");
        return panel;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        if (ae.getActionCommand().equals("Preview Table"))
            attributes.add(new MediaPrintableArea(6, 6, 198, 278, MediaPrintableArea.MM)); // A4: 210x297mm
            attributes.add(Sides.DUPLEX);
            attributes.add(OrientationRequested.LANDSCAPE);
            new PrintPreview(
                table.getPrintable(PrintMode.FIT_WIDTH, null, new MessageFormat("Page {0}") ), 
                printerJob.getPageFormat(attributes)
            );
    }

    public static void main(String arg[]) {
        new TestPreview();
    }
}

PrintPreview.java

package printpreviewdemo;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.print.*;

class PrintPreview extends JFrame implements ActionListener, ItemListener {
    JButton printButton = new JButton("Print");
    Pageable pageable = null;
    double scale = 1.0;
    Page page[] = null;
    JComboBox combobox = new JComboBox();
    CardLayout cardlayout = new CardLayout();
    JPanel previewPanel = new JPanel(cardlayout);
    JButton backButton = new JButton("PREV"), forwardButton = new JButton("NEXT");

    public PrintPreview(final Printable printable, final PageFormat pageFormat) {
        super("Print Preview");        
        pageable = new Pageable() {
            @Override
            public int getNumberOfPages() {
                Graphics graphics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).getGraphics();                
                int numPages = 0;
                try {
                    while (printable.print(graphics, pageFormat, numPages) == Printable.PAGE_EXISTS) {
                        numPages++;
                    }
                } catch (Exception ex) {
                }
                return numPages;
            }

            @Override
            public PageFormat getPageFormat(int x) {
                return pageFormat;
            }

            @Override
            public Printable getPrintable(int x) {
                return printable;
            }
        };
        createPreview();
    }

    private void createPreview() {
        page = new Page[pageable.getNumberOfPages()];
        PageFormat pageFormat = pageable.getPageFormat(0);
        Dimension size = new Dimension((int) pageFormat.getPaper().getWidth(), (int) pageFormat.getPaper().getHeight());
        if (pageFormat.getOrientation() != PageFormat.PORTRAIT) {
            size = new Dimension(size.height, size.width);
        }
        for (int i = 0; i < page.length; i++) {
            combobox.addItem("" + (i + 1));
            page[i] = new Page(i, size);
            previewPanel.add("" + (i + 1), new JScrollPane(page[i]));
        }
        setTopPanel();
        getContentPane().add(previewPanel, "Center");
        pack();
        setExtendedState(Frame.MAXIMIZED_BOTH);
        setVisible(true);
    }

    private void setTopPanel() {
        FlowLayout fl = new FlowLayout();
        GridBagLayout gbl = new GridBagLayout();

        JPanel topPanel = new JPanel(gbl), temp = new JPanel(fl);
        backButton.addActionListener(this);
        forwardButton.addActionListener(this);
        backButton.setEnabled(false);
        forwardButton.setEnabled(page.length > 1);

        temp.add(combobox);
        temp.add(backButton);
        temp.add(forwardButton);
        temp.add(printButton);

        topPanel.add(temp);
        printButton.addActionListener(this);
        combobox.addItemListener(this);
        getContentPane().add(topPanel, "North");
    }

    @Override
    public void itemStateChanged(ItemEvent ie) {
        cardlayout.show(previewPanel, (String) combobox.getSelectedItem());
        backButton.setEnabled(combobox.getSelectedIndex() == 0 ? false : true);
        forwardButton.setEnabled(combobox.getSelectedIndex() == combobox.getItemCount() - 1 ? false : true);
        validate();
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        Object o = ae.getSource();
        if (o == printButton) {
            try {
                PrinterJob pj = PrinterJob.getPrinterJob();
                pj.defaultPage(pageable.getPageFormat(0));
                pj.setPageable(pageable);
                if (pj.printDialog()) {
                    pj.print();
                }
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(null, ex.toString(), "Error in Printing", 1);
            }
        } else if (o == backButton) {
            combobox.setSelectedIndex(combobox.getSelectedIndex() == 0 ? 0 : combobox.getSelectedIndex() - 1);
            if (combobox.getSelectedIndex() == 0) {
                backButton.setEnabled(false);
            }
        } else if (o == forwardButton) {
            combobox.setSelectedIndex(combobox.getSelectedIndex() == combobox.getItemCount() - 1 ? 0 : combobox.getSelectedIndex() + 1);
            if (combobox.getSelectedIndex() == combobox.getItemCount() - 1) {
                forwardButton.setEnabled(false);
            }
        }
    }

    class Page extends JLabel {
        final int n;
        final PageFormat pageformat;
        BufferedImage bufferimage = null;
        Dimension size = null;

        public Page(int currentpage, Dimension size) {
            this.size = size;
            bufferimage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
            n = currentpage;
            pageformat = pageable.getPageFormat(n);
            Graphics g = bufferimage.getGraphics();
            g.setColor(Color.WHITE);                       
            g.fillRect(0, 0, (int) pageformat.getWidth(), (int) pageformat.getHeight());
            try {
                pageable.getPrintable(n).print(g, pageformat, n);
            } catch (Exception ex) {
            }
            setIcon(new ImageIcon(bufferimage));
        }
    }
}
John Astralidis
  • 357
  • 2
  • 4
  • 16

1 Answers1

0

Doubt if it's still of interest, but the problem is that TablePrintable is single-use. There's no way to reset it for a second pass.

Calling jTable.getPrintable() a second time gets a fresh TablePrintable, so you need to use the first for counting pages, and the second for actual printing.

Actually, you don't actually need to count the pages. getNumberofPages() can return zero; just end the print loop for when it runs out of pages.

An alternative workaround would be to copy the source of TablePrintable and add a reset method for variable 'last' and the Rectangle values.