Tuesday, October 11, 2005

Java Printing Again

After using the PrintUtilities class in my previous post I found it was a bit rough in places so I've made some improvements.

The component is now scaled to the page width and there is a away to set a title that is drawn on the printed output. The title stuff is a little limited, one line only, no font control etc. But it does what I need it to do for the moment.


package au.com.phasefale.utils.printing;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.RepaintManager;

/**
*
* PrintUtilities
*
* Originally taken from
* http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-Printing.html
*
* Improved so that component is scaled to page width. Title can be added to the top of the printed
* output.
*
* Created On: 11/10/2005
*
*/

public class PrintUtilities implements Printable {
private Component componentToBePrinted;
private String titleForComponent;

public static void printComponent(Component c) {
new PrintUtilities(c).print();
}

public PrintUtilities(Component componentToBePrinted) {
this.componentToBePrinted = componentToBePrinted;
}

public PrintUtilities(Component componentToBePrinted, String title) {
this.componentToBePrinted = componentToBePrinted;
this.titleForComponent = title;
}

public void setTitle(String title) {
this.titleForComponent = title;
}

public void print() {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(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) {
return (NO_SUCH_PAGE);
} else {
Graphics2D g2 = (Graphics2D) g;

g2.setColor(Color.black);
int fontHeight = (titleForComponent == null) ? 0 : g2.getFontMetrics().getHeight();
int fontDesent = (titleForComponent == null) ? 0 : g2.getFontMetrics().getDescent();
int stringWidth = (titleForComponent == null) ? 0 : (int) g2.getFontMetrics()
.getStringBounds(titleForComponent, g2).getWidth();

// double pageHeight = pageFormat.getImageableHeight() - fontHeight;
double pageWidth = pageFormat.getImageableWidth();
double componentWidth = (double) componentToBePrinted.getWidth();
double scale = 1;
if (componentWidth >= pageWidth) {
scale = pageWidth / componentWidth;
}

g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
if (titleForComponent != null) {
int x = (int) pageWidth / 2 - stringWidth / 2;
int y = fontHeight;
g2.drawString(titleForComponent, x, y);
g2.translate(0, y + fontDescent);

// The following print string at bottom of page
// no need to translate either
// g2.drawString(titleForComponent, (int) pageWidth / 2 - stringWidth / 2,
// (int) (pageHeight + fontHeight - fontDesent));
}

g2.scale(scale, scale);
disableDoubleBuffering(componentToBePrinted);
componentToBePrinted.paint(g2);
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);
}
}


Java Printing.

Documentation on the Java Printing API is pretty sparse. However I have finally come across a decent document on it. This link explains how to print a Java component. The crux of it comes down to this code which I'm going to repost here just incase the link dies (NB I'm not taking credit for the code below).

I've previously had high quality printing out of Java using Graphics2D, however I had odd problems when using animated gifs in the App at the same time. The gifs would come up in the printing output, not surprisingly double buffering was causing the problem.

import java.awt.*;
import javax.swing.*;
import java.awt.print.*;

public class PrintUtilities implements Printable {
private Component componentToBePrinted;

public static void printComponent(Component c) {
new PrintUtilities(c).print();
}

public PrintUtilities(Component componentToBePrinted) {
this.componentToBePrinted = componentToBePrinted;
}

public void print() {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(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) {
return(NO_SUCH_PAGE);
} else {
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
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);
}
}

Thursday, October 06, 2005

JTree row truncation problem

Been having a problem (not a huge one) with a JTree on a JScrollPane in a JSplitPane using an extension of DefaultTreeCellRenderer.

When the cells of the tree containing strings, where made longer they tended to get truncated with "..." despite there being enough room in the JSplitPane to accommodate the change and that it would have been possible to add a scroll bar.

After a whole lot of stuffing around and trawling search engines I found the solution here. The second to last post contains the solution.

tree.setLargeModel(true);

tree.setRowHeight( [non-zero positive value] );


I turns out that JTree caches the cell dimensions, not surprising if you see the problem occurring. So by setting the above fields it seems to turn the caching off. Trade off being that the row height is fixed.

I haven't investigated if using a custom implementation of TreeCellRender that uses a JPanel rather than a JLabel to work better, but since I'm using icons it would mean replicating much of what JLabel does.

This page is powered by Blogger. Isn't yours?