Printing a Jframe and Its Components

Printing a JFrame and its components

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

Printing selected Component of JFrame to Printer

A few minutes spent reading How to use tables/printing, would have allowed you to produce something similar to this example...

Printed output...

Printed

Screen output...

Screen

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PrinterException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;

public class CopyTable {

public static void main(String[] args) {
new CopyTable();
}

public CopyTable() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JTable table;
private JTextField customer;
private JSpinner date;

public TestPane() {

DefaultTableModel model = new DefaultTableModel();
for (int index = 0; index < 26; index++) {
model.addColumn((char) (index + 65));
}

for (int row = 0; row < 26; row++) {
Vector rowData = new Vector();
for (int col = 0; col < 26; col++) {
rowData.add(row + "x" + col);
}
model.addRow(rowData);
}

table = new JTable(model);

Calendar calendar = Calendar.getInstance();
Date initDate = calendar.getTime();
Date earliestDate = calendar.getTime();
calendar.add(Calendar.YEAR, 200);
Date latestDate = calendar.getTime();
SpinnerModel spinnerModel = new SpinnerDateModel(
initDate,
earliestDate,
latestDate,
Calendar.YEAR);

date = new JSpinner();
date.setModel(spinnerModel);
date.setEditor(new JSpinner.DateEditor(date, "dd/MM/yyyy"));

customer = new JTextField(10);

setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;

add(new JLabel("Customer:"), gbc);
gbc.gridy++;
add(new JLabel("Date:"), gbc);

gbc.gridy = 0;
gbc.gridx++;
gbc.weightx = 1;
gbc.anchor = GridBagConstraints.WEST;
add(customer, gbc);
gbc.gridy++;
add(date, gbc);

gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
add(new JScrollPane(table), gbc);
gbc.gridx = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.CENTER;
JButton print = new JButton("Print");
add(print, gbc);

print.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
MessageFormat header = new MessageFormat("Customer: " + customer.getText() + " | Date: " + new SimpleDateFormat("dd/MM/yyyy").format(date.getValue()));
try {
table.print(JTable.PrintMode.FIT_WIDTH, header, null, true, null, true);
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
});

}

}
}

Printing a large Swing component

Since a component in a JScrollPane can have arbitrary size, even after it is made displayable, My solution is to try this:

JPanel c = createPanel();
JFrame f = new JFrame();
f.getContentPane().add(new JScrollPane(c));
f.pack();
print(c);

so that I can validate the JPanel without it being size-limited to the maximum size of a JFrame. It also has the "unlimited resolution" look on the fonts and things that you get from printing the components directly, without double-buffering like trashgod suggested.

How can I print a single JPanel's contents?

Here is an example to print any Swing component.

public void printComponenet(Component component){
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");

pj.setPrintable (new Printable() {
public int print(Graphics pg, PageFormat pf, int pageNum){
if (pageNum > 0){
return Printable.NO_SUCH_PAGE;
}

Graphics2D g2 = (Graphics2D) pg;
g2.translate(pf.getImageableX(), pf.getImageableY());
component.paint(g2);
return Printable.PAGE_EXISTS;
}
});
if (pj.printDialog() == false)
return;

try {
pj.print();
} catch (PrinterException ex) {
// handle exception
}
}

printing a 2 pages of jframe in java

So, the first thing we need to is make sure that the component been printed is at it's preferred size...

component.setSize(component.getPreferredSize());

This is important, but also remember, that this will affect the component that is on the screen...

Next, we need to work out if we are printing a new page or re-printing the current page. This occurs because print might be called multiple times for a given page...

if (lastPage != pageIndex) {
lastPage = pageIndex;
//...
}

We then need to calculate the y offset of the component that fits the current page...

yOffset = height * pageIndex;
if (yOffset > component.getHeight()) {
yOffset = -1;
}

If the yOffset is greater then the component height, then we don't want to print any more pages.

Next, we print the page, to do this, we need to translate the Graphics context so that the yOffset becomes the new 0 position...

g2d.translate(0, -yOffset);

Then we print the component...

component.printAll(g2d);

For example...

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.PrinterResolution;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PrintMe {

public static void main(String[] args) {
new PrintMe();
}

public PrintMe() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

TestPane testPane = new TestPane();

JButton btn = new JButton("Print");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(MediaSizeName.ISO_A4);
aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));

PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(new MultiPagePrintable(testPane));

if (pj.printDialog(aset)) {
try {
pj.print(aset);
testPane.getParent().invalidate();
testPane.getParent().validate();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
}
});

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(testPane));
frame.add(btn, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel implements Scrollable {

private BufferedImage img;

public TestPane() {
try {
img = ImageIO.read(new File("Get your own image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}

@Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}

@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 200);
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}

@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}

@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}

}

public class MultiPagePrintable implements Printable {

private JComponent component;
private int lastPage = 0;
private double yOffset;

public MultiPagePrintable(JComponent component) {
this.component = component;
}

@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = NO_SUCH_PAGE;

double height = pageFormat.getImageableHeight();
component.setSize(component.getPreferredSize());

if (lastPage != pageIndex) {
lastPage = pageIndex;
yOffset = height * pageIndex;
if (yOffset > component.getHeight()) {
yOffset = -1;
}
}

if (yOffset >= 0) {
Graphics2D g2d = (Graphics2D) graphics;

g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());

g2d.translate(0, -yOffset);
component.printAll(g2d);
result = PAGE_EXISTS;
}
return result;
}

}

}

Now, this example only prints in the vertical direction, if you need it to print the horizontal direction as well, it gets a little more complicated, but that the basic concept remains the same

How can I pack() a printable Java Swing component?

You could use invalidate(), which will cause validate() to invoke validateTree(); alternatively, use validateTree() directly.

@TacB0sS seems to make a good point: simply don't invoke setVisible(); this related previous question is cited for reference.



Related Topics



Leave a reply



Submit