2

I'm nervous about asking this because I'm scared I'll get told off. I am trying to print a JPanel that is about 4 pages long. It could be more, the data is from a JDBC MySql query, that could end up being many more that 4. The JPanel I am trying to print is full of other JPanels (with competitors race details on them) that I have added via a ListArray..

Anyway, I have scoured all day through stackoverflow and have found may examples of code that I have tried to implement. The printable class only prints the first page, so I have tried to implement the pageable class, but I just can't seem to get it right. I have tried to implement the Book class but don't know how to add my JPanel to the book. I have looked here, here and many more (I'm only allowed to post 2 links). Here is my current code (that I got off one of the answers that @madprogrammer gave) -

int printButton = JOptionPane.showOptionDialog(null, scrollPane, "Race Winners", JOptionPane.YES_NO_OPTION,
        JOptionPane.PLAIN_MESSAGE, // no Icon
        null, //do not use a custom Icon
        options, //the titles of buttons
        options[0]); //default button title

if (printButton == 0) {
    try {
        printComponent(pane, true);

        //printComponentToFile(pane, false);

    } catch (PrinterException exp) {
        exp.printStackTrace();
    }

    public static void printComponent(JComponent comp, boolean fill) throws PrinterException {
        PrinterJob pjob = PrinterJob.getPrinterJob();
        //pjob.setPageable(comp);
        PageFormat pf = pjob.defaultPage();
        pf.setOrientation(PageFormat.PORTRAIT);

        PageFormat postformat = pjob.pageDialog(pf);

        if (pf != postformat) {
            //Set print component
            //pjob.setPageable(comp);
            pjob.setPrintable(new ComponentPrinter(comp, fill), postformat);

            if (pjob.printDialog()) {
                pjob.print();
            }
        }
    }

    public static void printComponentToFile(Component comp, boolean fill) throws PrinterException {
        Paper paper = new Paper();
        paper.setSize(8.3 * 72, 11.7 * 72);
        paper.setImageableArea(18, 18, 559, 783);

        PageFormat pf = new PageFormat();
        pf.setPaper(paper);
        pf.setOrientation(PageFormat.PORTRAIT);

        BufferedImage img = new BufferedImage(
        (int) Math.round(pf.getWidth()), (int) Math.round(pf.getHeight()),
        BufferedImage.TYPE_INT_RGB);

        Graphics2D g2d = img.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
        ComponentPrinter cp = new ComponentPrinter(comp, fill);

        try {
            cp.print(g2d, pf, 0);
        } finally {
            g2d.dispose();
        }

        try {
            ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static class ComponentPrinter implements Printable, Pageable {
        private Component comp;
        private boolean fill;
        int numPages;
        PageFormat format;


        public ComponentPrinter(Component comp, boolean fill) {
            this.comp = comp;
            this.fill = fill;
        }

        @Override
        public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {

            numPages = (int) Math.ceil(comp.getHeight() / format.getImageableY());
            System.out.print(numPages);

            if (page_index > 0) {
                return Printable.NO_SUCH_PAGE;
            }

            Graphics2D g2 = (Graphics2D) g;
            g2.translate(format.getImageableX(), format.getImageableY());
            //g2.translate(format.getImageableX(), format.getImageableY()- page_index*comp.getPreferredSize().height);

            double width = (int) Math.floor(format.getImageableWidth());
            double height = (int) Math.floor(format.getImageableHeight());

            if (!fill) {

                width = Math.min(width, comp.getPreferredSize().width);
                height = Math.min(height, comp.getPreferredSize().height);

            }

            comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
            if (comp.getParent() == null) {
                comp.addNotify();
            }
            comp.validate();
            comp.doLayout();
            comp.printAll(g2);
            if (comp.getParent() != null) {
                comp.removeNotify();
            }

            return Printable.PAGE_EXISTS;
        }
        @Override
        public int getNumberOfPages() {
            // TODO Auto-generated method stub
            return numPages;
        }
        @Override
        public PageFormat getPageFormat(int arg0) throws IndexOutOfBoundsException {
            return format;
        }
        @Override
        public Printable getPrintable(int arg0) throws IndexOutOfBoundsException {
            // TODO Auto-generated method stub
            return this;
        }
}

This all works, but only prints the first page. I would REALLY appreciate a nudge in the right direction with this as I'm stumped. TIA :-)

Community
  • 1
  • 1
AngeKing
  • 69
  • 6

1 Answers1

0

This is how you print a Component (JPanel) on multiple pages:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.*;

import javax.swing.RepaintManager;

public class PrintMultiPageUtil implements Printable, Pageable {
    private Component componentToBePrinted;
    private PageFormat format;
    private int numPages;

    public PrintMultiPageUtil(Component componentToBePrinted) {
        this.componentToBePrinted = componentToBePrinted;

        // get total space from component  
        Dimension totalSpace = this.componentToBePrinted.getPreferredSize();

        // calculate for DIN A4
        format = PrinterJob.getPrinterJob().defaultPage();
        numPages = (int) Math.ceil(totalSpace .height/format.getImageableHeight());
    }

    public void print() {
        PrinterJob printJob = PrinterJob.getPrinterJob();

        // show page-dialog with default DIN A4
        format = printJob.pageDialog(printJob.defaultPage());

        printJob.setPrintable(this);
        printJob.setPageable(this);

        if (printJob.printDialog())
            try {
                printJob.print();
            } catch(PrinterException pe) {
                System.out.println("Error printing: " + pe);
            }
    }

    public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
        if ((pageIndex < 0) | (pageIndex >= numPages)) {
            return(NO_SUCH_PAGE);
        } else {
            Graphics2D g2d = (Graphics2D)g;
            g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY() - pageIndex * pageFormat.getImageableHeight());
            disableDoubleBuffering(componentToBePrinted);
            componentToBePrinted.paint(g2d);
            enableDoubleBuffering(componentToBePrinted);
            return(PAGE_EXISTS);
        }
    }

    public static void disableDoubleBuffering(Component c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(false);
    }

    public static void enableDoubleBuffering(Component c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(true);
    }

    @Override
    public int getNumberOfPages() {
        // TODO Auto-generated method stub
        return numPages;
    }

    @Override
    public PageFormat getPageFormat(int arg0) throws IndexOutOfBoundsException {
        return format;
    }

    @Override
    public Printable getPrintable(int arg0) throws IndexOutOfBoundsException {
        // TODO Auto-generated method stub
        return this;
    }
}

numPages

I changed the expression for numPages to:

(int) Math.ceil(page.height/format.getImageableHeight())

This divides the total height (height of the jpanel) through the height of one page, thus calculating the number of all pages.

g2d.translate

I did the following change: In this line:

g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY() - pageIndex * pageFormat.getImageableHeight());

Changed componentToBePrinted.getPreferredSize().height to pageFormat.getImageableHeight(). A positive value for the first or the second parameter of g2d.translate moves the graphic to the right or down respectively.

.getImageableX() and .getImageableY() help position the graphic so that it doesn't overlap with the padding.

For pageIndex greater than 0, - pageIndex * pageFormat.getImageableHeight() moves the image pageIndex-times the page-height to the top. So the area, that the pageIndex refers to is printed.

original broken source:: https://community.oracle.com

Here is my original answer.

ArchLinuxTux
  • 840
  • 1
  • 11
  • 28