As shown in this answer you can create a new JTable
and pass it as the component to the getImageFromComponent(...)
and it's header appart:

java.awt.Image img = getImageFromComponent(table.getTableHeader());
addImageToDocument(img);
img = getImageFromComponent(table);
addImageToDocument(img);
That in case you don't add the JTable
to a JScrollPane
, if you do, then you send the JScrollPane
, for example:

java.awt.Image img = getImageFromComponent(scrollPane);
addImageToDocument(img);
It's up to you how you add the table... I prefer the scrollPane
version :)
Another way would be to iterate through the JTable
's data and use PdfPTable
.
Based on this answer you can get something like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class JTableToPdf {
private JFrame frame;
private JTable table;
private JButton button;
private Document document;
private PdfWriter writer;
private JScrollPane scrollPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JTableToPdf().createAndShowGui();
}
});
}
public void openPdf() throws FileNotFoundException, DocumentException {
document = new Document(PageSize.A4, 30, 30, 30, 30);
writer = PdfWriter.getInstance(document, new FileOutputStream("myFile2.pdf"));
document.open();
}
public void closePdf() {
document.close();
}
public void addData(PdfPTable pdfTable) throws DocumentException {
pdfTable.setHeaderRows(1);
PdfPCell cell = new PdfPCell(new Paragraph(table.getColumnName(0)));
cell.setBackgroundColor(new GrayColor(0.7f));
pdfTable.addCell(cell);
cell = new PdfPCell(new Paragraph(table.getColumnName(1)));
cell.setBackgroundColor(new GrayColor(0.7f));
pdfTable.addCell(cell);
cell = new PdfPCell(new Paragraph(table.getColumnName(2)));
cell.setBackgroundColor(new GrayColor(0.7f));
pdfTable.addCell(cell);
for (int i = 0; i < table.getRowCount(); i++) {
for (int j = 0; j < table.getColumnCount(); j++) {
pdfTable.addCell(table.getModel().getValueAt(i, j).toString());
}
}
document.add(pdfTable);
}
public void createAndShowGui() {
frame = new JFrame("PDF creator");
int rows = 100;
int cols = 3;
String data [][] = new String[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
data[i][j] = i + "-" + j;
}
}
table = new JTable(data, new String []{"A", "B", "C"});
table.setBorder(BorderFactory.createLineBorder(Color.RED));
button = new JButton("Create PDF");
scrollPane = new JScrollPane(table);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
PdfPTable pdfTable = new PdfPTable(table.getColumnCount());
openPdf();
addData(pdfTable);
closePdf();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (DocumentException e1) {
e1.printStackTrace();
}
}
});
// frame.add(table.getTableHeader(), BorderLayout.NORTH);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

If you don't want the header to repeat on every page just remove the lines before the for
loops on addData(...)
method.
A third method could be using the JTable
's printable
methods, but I don't own a printer here, I'll work on this sample later, since I don't have much time at the moment and I'm not sure how to integrate that with iText so I must search a little...
PHEW! It took me a while to create this result, but I think it works nice (though you need to restore the JTable
after creating the PDF).
Have a look at the code comments and tell me if this helps. I combined the use of the PDFPTable
and the image approach to get to this new approach:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class JTable2Pdf {
private JFrame frame;
private JTable table;
private JButton button;
private JScrollPane scrollPane;
private DefaultTableModel model;
private DefaultTableModel restoreModel;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JTable2Pdf().createAndShowGui();
}
});
}
public void restoreTableView() {
table.setModel(restoreModel);
frame.revalidate();
frame.repaint();
}
public void createAndShowGui() {
frame = new JFrame("PDF creator");
int rows = 130;
int cols = 3;
String data[][] = new String[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
data[i][j] = i + "-" + j;
}
}
model = new DefaultTableModel(data, new String[] { "A", "B", "C" });
restoreModel = new DefaultTableModel(data, new String[] { "A", "B", "C" });
table = new JTable(model);
//Just some borders for the table and its header
table.setBorder(BorderFactory.createLineBorder(Color.RED));
table.getTableHeader().setBorder(BorderFactory.createLineBorder(Color.RED));
scrollPane = new JScrollPane(table);
button = new JButton("Create PDF");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
//We create an instance of pdfCreator and pass our JTable as instance
PdfCreator pdfCreator = new PdfCreator(table);
//We open the pdf and say we want to repeat the header for each page
pdfCreator.openPdf(true);
//Then we add the header (if we don't add it first, then the 1st row of the table will be the one repeating over the pages
pdfCreator.addImageToTable(pdfCreator.getImageFromComponent(table.getTableHeader()));
//Then we add the rows to the PDF
pdfCreator.getRowsImage();
//Finally we close the PDF
pdfCreator.closePdf();
//And last we restore the table
restoreTableView();
} catch (DocumentException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class PdfCreator {
private JTable table;
private Document document;
private PdfWriter writer;
private boolean isNewPage;
private PdfPTable pdfTable;
public PdfCreator(JTable table) {
this.table = table;
}
//This method opens the PDF, repeatHeader if true, adds the header to each page, otherwise it only adds it to the 1st one
public void openPdf(boolean repeatHeader) throws FileNotFoundException, DocumentException {
document = new Document(PageSize.A4, 30, 30, 30, 30);
writer = PdfWriter.getInstance(document, new FileOutputStream("myFile.pdf"));
pdfTable = new PdfPTable(1);
if (repeatHeader) {
pdfTable.setHeaderRows(1);
}
pdfTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
pdfTable.getDefaultCell().setPadding(0);
document.open();
}
//This method closes the document
public void closePdf() {
document.close();
}
//This method gets the image for each row recursively
//As this method gets the graphics for the table from 0, 0 to the width and length determined, we need to remove the 1st row of the table
//each time we go through it and that's why we need to restore the table model later in the code
public void getRowsImage() throws DocumentException, IOException {
if (table.getRowCount() > 0) {
int width = table.getCellRect(0, 0, true).width + table.getCellRect(0, 1, true).width + table.getCellRect(0, 2, true).width;
int height = table.getCellRect(0, 0, true).height;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
table.paint(img.getGraphics());
DefaultTableModel dtm = (DefaultTableModel) table.getModel();
System.out.println(table.getRowCount() + " - " + isNewPage);
dtm.removeRow(0);
addImageToTable(img);
getRowsImage();
} else {
document.add(pdfTable);
}
}
//This gets the image for the table header and / or any other components you need to add to the PDF
public java.awt.Image getImageFromComponent(JComponent component) throws DocumentException {
int width = component.getWidth();
int height = component.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
component.paint(image.getGraphics());
return image;
}
//This method add the image to a PDFPTable which will be added later to the document
public void addImageToTable(java.awt.Image img) throws IOException, DocumentException {
Image image = Image.getInstance(writer, img, 1);
image.scalePercent(100);
pdfTable.addCell(image);
System.out.println("printed!");
}
}
These are the outputs:
1st page with borders and repeating header
2nd page with borders and repeating header

2nd page with borders and not repeating header

1st page with no borders and not repeating header
2nd page with no borders and not repeating header

I was able to change the above code by moving and not removing the rows this produces the same result and it's still working the same, but you no longer need the restoreTableView()
method... Just change the getRowsImage()
method as follows:
public void getRowsImage() throws DocumentException, IOException {
if (movedRows < table.getRowCount()) {
int width = table.getCellRect(0, 0, true).width + table.getCellRect(0, 1, true).width + table.getCellRect(0, 2, true).width;
int height = table.getCellRect(0, 0, true).height;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
table.paint(img.getGraphics());
DefaultTableModel dtm = (DefaultTableModel) table.getModel();
System.out.println(table.getRowCount() + " - " + isNewPage);
dtm.moveRow(0, 0, table.getRowCount() - 1);
movedRows++;
addImageToTable(img);
getRowsImage();
} else {
document.add(pdfTable);
}
}
And declare a variable movedRows = 0
as a class member for the PdfCreator
class :)