Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing a JFrame and its components

I have been working in a big program and one of its functionalities should be to print the contents of the main window. I checked the API and found this example:

http://docs.oracle.com/javase/tutorial/2d/printing/gui.html

it was very helpful, I tried to use that code in my program by placing this inside the actionperformed method of my print button:

PrinterJob job = PrinterJob.getPrinterJob();
     job.setPrintable(this);
     boolean ok = job.printDialog();
     if (ok) {
         try {

             job.print();
         } catch (PrinterException ex) {
          /* The job did not successfully complete */
         }
     }

If I click the print button, I get a printer dialog and when I tell it to print, it just prints a blank document. I know the above code is not all I need, as I've seen in the API's examples there is a print() method, but apparently they never call it, so it is pretty confusing. I've tried calling and using it many times, but with no success.

Also, I think that when I finally get it to print, my window will need to be printed in the landscape orientation, it even may need some scaling. Any ideas on how to do that?

I would like any useful help to help me implement this code successfully. I know I should be able to do it by myself just by checking the documentation (I've tried for almost 2 days now) but I can't get it to work. I've learned all the programming I know through the internet. Any help will be greatly appreciated.

like image 294
Alex Terreaux Avatar asked Oct 06 '12 23:10

Alex Terreaux


People also ask

What are the components of JFrame?

The JFrame API. classes and include pack , setSize , show , hide , setVisible , setTitle , and getTitle . Much of the operation of a frame is managed by other objects. For example, the interior of a frame is managed by its root pane, and the content pane contains the frame's GUI.

How do I print a JFrame?

Print JFrame with components coderanch.com print //Method called from Print Button public void FilePrintClicked(){ PrinterJob job = PrinterJob. getPrinterJob(); PageFormat format = job. defaultPage(); format.

What is JFrame frame?

A frame, implemented as an instance of the JFrame class, is a window that has decorations such as a border, a title, and supports button components that close or iconify the window. Applications with a GUI usually include at least one frame. Applets sometimes use frames, as well.

Is JFrame a Swing component?

JFrame class inherits the java. awt. Frame class. JFrame is like the main window of the GUI application using swing.


2 Answers

Here's a simple solution. I have a Printer class that implements printable and it will handle the printing job:

public static class Printer implements Printable {
    final Component comp;

    public Printer(Component comp){
        this.comp = comp;
    }

    @Override
    public int print(Graphics g, PageFormat format, int page_index) 
            throws PrinterException {
        if (page_index > 0) {
            return Printable.NO_SUCH_PAGE;
        }

        // get the bounds of the component
        Dimension dim = comp.getSize();
        double cHeight = dim.getHeight();
        double cWidth = dim.getWidth();

        // get the bounds of the printable area
        double pHeight = format.getImageableHeight();
        double pWidth = format.getImageableWidth();

        double pXStart = format.getImageableX();
        double pYStart = format.getImageableY();

        double xRatio = pWidth / cWidth;
        double yRatio = pHeight / cHeight;


        Graphics2D g2 = (Graphics2D) g;
        g2.translate(pXStart, pYStart);
        g2.scale(xRatio, yRatio);
        comp.paint(g2);

        return Printable.PAGE_EXISTS;
    }
}

Next, to print it:

JFrame yourComponent = new JFrame();
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat preformat = pjob.defaultPage();
preformat.setOrientation(PageFormat.LANDSCAPE);
PageFormat postformat = pjob.pageDialog(preformat);
//If user does not hit cancel then print.
if (preformat != postformat) {
    //Set print component
    pjob.setPrintable(new Printer(yourComponent), postformat);
    if (pjob.printDialog()) {
        pjob.print();
    }
}
like image 74
user1401250 Avatar answered Nov 06 '22 07:11

user1401250


Here's my twist on the idea...

Print to fit...

A4-Fit

Print to fill...

A4-Fill

public class TestPrinting {

    public static void main(String[] args) {    
        try {
            printComponentToFile(new PrintForm(), true);
            printComponentToFile(new PrintForm(), false);
        } catch (PrinterException exp) {
            exp.printStackTrace();
        }
    }

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

        PageFormat postformat = pjob.pageDialog(pf);
        if (pf != postformat) {
            //Set print component
            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.LANDSCAPE);

        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 {

        private Component comp;
        private boolean fill;

        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 {

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

            Graphics2D g2 = (Graphics2D) g;
            g2.translate(format.getImageableX(), format.getImageableY());

            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;
        }

    }

}

Some of the wider ranging issues...

  • You become responsible for the layout of the components been printed, more or less. At least you will want to make sure that they either fit or you have some kind of overflow mechanism worked out...
  • You may need to "trick" components that haven't already been displayed on the screen into thinking that they are...hence all the mucky around with addNotify/validate/doLayout. Even when displayed on the screen, if you modify their bounds, you may need to call these methods.
like image 26
MadProgrammer Avatar answered Nov 06 '22 08:11

MadProgrammer