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_IN