0

I am able to save a jtable on pdf but table comes without a header please help me :

  Document document = new Document(PageSize.A4, 50.0f, 50.0f, 10.0f, 50.0f);
            PdfWriter writer = PdfWriter.getInstance((Document)document,      (OutputStream)new FileOutputStream(this.file + ".pdf"));
              document.open();
               PdfContentByte cb1 = writer.getDirectContent();
         // modules table
              PdfTemplate template = cb1.createTemplate(2480.0f, 3500.0f);   
                  Graphics2D g1 =        template.createGraphics((float)this.jTable_Modules2.getWidth(),        (float)this.jTable_Modules2.getHeight());
   //                       this.jTable_Modules2.getViewport().setBackground(Color.WHITE);
             this.jTable_Modules2.print(g1);
                g1.dispose();
            com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance((PdfTemplate)template);
            image.scalePercent(60.0f);
            image.setAbsolutePosition(80.0f, 458.0f);

             document.add((Element)image);

   document.close();
            JOptionPane.showMessageDialog(null, "Transcript successfully generated");
user3518835
  • 107
  • 1
  • 3
  • 10
  • 1
    *"plz hepl me :"* Please write complete words (and spell them correctly). Please post a valid [mcve] which demonstrates your issue (correctly indented). :) – Frakcool Mar 01 '17 at 14:49

1 Answers1

2

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:

enter image description here

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:

enter image description here

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

enter image description here enter image description here

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 enter image description here 2nd page with borders and repeating header enter image description here

2nd page with borders and not repeating header enter image description here

1st page with no borders and not repeating header enter image description here 2nd page with no borders and not repeating header enter image description here


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 :)

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • How well does that handle long/wide tables? Does it automatically re-add the header for each new page? – MadProgrammer Mar 01 '17 at 21:24
  • @MadProgrammer actually no, I didn't took into consideration long / wide tables in the sample I did. I'm working on a better solution when the table is too large because it crops the image on the page end. – Frakcool Mar 01 '17 at 21:43
  • I'm wondering if you can use the table's `printable` support or not... – MadProgrammer Mar 01 '17 at 21:51
  • @MadProgrammer interesting, let me see what can I do :) – Frakcool Mar 01 '17 at 22:09
  • @MadProgrammer please see edit, I got another way to solve this, however it wasn't using the table's `printable` functions... I don't know how to do it – Frakcool Mar 01 '17 at 23:26
  • 1
    Well, it's a start, expect if they have custom cell renders ;) – MadProgrammer Mar 01 '17 at 23:30
  • @Frakcool , great job. but the problem i own is that when a jScroll is short and the table is long, when you save a pdf , Function slices where jscroll ends . but when you save a jtabe as image on pdf however it comes entire. thanks anyway ,if you would be near i could shake your hand . – user3518835 Mar 02 '17 at 14:23
  • @user3518835 I'm still trying another solution converting the table to an image, how many rows and cols does your table has? – Frakcool Mar 02 '17 at 14:31
  • @Frakcool around fifteen rows for each table among free tables on the A4 paper. and another problem is that table columns are of equal width . – user3518835 Mar 02 '17 at 14:48
  • @Frakcool , according to my code above, i don't see how to use the following one of yours: `java.awt.Image img = getImageFromComponent(table.getTableHeader()); addImageToDocument(img); img = getImageFromComponent(table); addImageToDocument(img);` – user3518835 Mar 02 '17 at 15:09
  • @user3518835 1) your code is incomplete, we need you to post a correctly indented [mcve] the code I provided is an example of it, you can copy-paste it, run it and see the output. I'm a little busy right now, when I'm a little more free of time I'll come back to provide more help – Frakcool Mar 02 '17 at 15:17
  • @MadProgrammer See new edit, do you have a better idea to improve the last code, so you don't need to "restore" the `JTabel` model after iterating through the rows to create the PDF this way? I've had no luck using the `printable` methods yet but I came with this idea :) – Frakcool Mar 03 '17 at 02:29