How to save a jtable on pdf with a jtable header

后端 未结 1 1672
被撕碎了的回忆
被撕碎了的回忆 2020-12-20 09:18

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.         


        
相关标签:
1条回答
  • 2020-12-20 10:12

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

    0 讨论(0)
提交回复
热议问题