Saturday, May 4, 2013

Printing the Contents of a JTextArea

Last week I needed to print the contents of a JTextArea.  When I looked online for examples it was scarce and what I thought would be an easy task (like 5 minutes) turned into a 3 hour event.

There were a few reasons for this.  The first is that there were examples, but they were all dated. They were created for Java 1.4 and who still develops with Java 1.5 or older?  Secondly, some of the examples, particularly on Stack Overflow, took you down the path of using Graphics2D which isn't what I wanted since it only printed the displayable portion of your JTextArea.

Then I found the TextAreaPrintingDemo on the Java Tutorials site.  It helped out a lot.  Here's my final result.

private class PrintingTask extends SwingWorker<Object, Object> {

    private final MessageFormat headerFormat;
    private final MessageFormat footerFormat;
    private final boolean interactive;
    private volatile boolean complete = false;
    private volatile String message;

    public PrintingTask(MessageFormat header, MessageFormat footer,
            boolean interactive) {
        this.headerFormat = header;
        this.footerFormat = footer;
        this.interactive = interactive;
    }

    @Override
    protected Object doInBackground() {
        try {
            reportTextPane.setFont(printableFont);
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
            attributes.add(new MediaPrintableArea(0.5f, 0.5f, 7.5f, 10.0f, MediaPrintableArea.INCH));
            complete = reportTextPane.print(headerFormat, footerFormat,
                    true, null, attributes, interactive);
            reportTextPane.setFont(viewableFont);
            message = "Printing " + (complete ? "complete" : "canceled");
        } catch (PrinterException ex) {
            message = "Sorry, a printer error occurred";
        } catch (SecurityException ex) {
            message = "Sorry, cannot access the printer due to security reasons";
        }
        return null;
    }

    @Override
    protected void done() {
        message(!complete, message);
    }
}

private void message(boolean error, String msg) {
    int type = (error ? JOptionPane.ERROR_MESSAGE
            : JOptionPane.INFORMATION_MESSAGE);
    JOptionPane.showMessageDialog(this, msg, "Printing", type);
}

private void error(String msg) {
    message(true, msg);
}

public void print() {
    MessageFormat header = new MessageFormat("This is the Title");
    MessageFormat footer = new MessageFormat("Page {0}");
    boolean interactive = true;
    boolean background = true;
    PrintingTask task = new PrintingTask(header, footer, interactive);
    if (background) {
        task.execute();
    } else {
        task.run();
    }
}
I did find that once I started printing that the text size didn't render on the printer the same as viewed in the JTextArea. A hack I did to work around this was to set the font smaller (10) and return it to the original size (12) when it was finished. I'd like a cleaner method for rendering the print size a bit better. Any suggestions?