如何横跨多个页面跨越宽表?

时间:2014-02-01 18:53:56

标签: java pdf itext tabular

我正在寻找一种方法来拆分宽表,以便它们跨越多个页面。目标是使具有大量列的表可读。我发现了一个discussion thread where this topic is covered;但是,那里引用的示例不可用。 Manning的“iText in Action”(2006)并未涵盖此主题。

这可以在版本1.4.8中完成,如果没有,我应该升级到哪个版本的iText?

3 个答案:

答案 0 :(得分:2)

请查看chapter 4 of my book的示例,更具体地说,请参阅Zhang示例。在这个例子中,我有一个包含四列的表:(1)年份,(2)英文电影片名,(3)中文电影片名,以及(4)游程长度。如果查看生成的PDF,您将看到此表是垂直分割的。

实现这一点需要更多的工作,然后只需添加一个表并允许iText决定如何在行之间拆分它。如果要在列之间拆分,则需要在代码中组织布局。这是使用writeSelectedRows())方法完成的。

在我的简单书籍示例中,我使用以下几行:

// draw the first two columns on one page
table.writeSelectedRows(0, 2, 0, -1, 236, 806, canvas);
document.newPage();
// draw the remaining two columns on the next page
table.writeSelectedRows(2, -1, 0, -1, 36, 806, canvas);

首先,我将索引0的列绘制到索引2.索引为0的列是第一列,索引为2的列是未包含的第一列,即第三列。我从索引0(第一行)绘制行直到-1。减去一个意味着:绘制所有剩余的行。

你还会在下一页看到减号,在那里我用索引2(第三列)绘制列,直到索引为-1的列(意思是:其余列)。

值(236,806)和(36,806)是坐标:这是您希望表开始的位置。您无法定义“结束坐标”。如果表格不适合页面,iText将继续绘制表格,即使这意味着某些内容超出了页面的可见区域。这意味着在使用此方法时您必须非常小心:在添加表之前,您需要计算行和列的宽度和高度,否则您可能会得到表中不可见的部分。

答案 1 :(得分:1)

这是一个类的source code,当您的列不适合单个页面时,会将您的表格拆分为多个页面

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

/**
 * Class that writes a <code>PdfPTable</code>, and spans it across multiple
 * pages if the columns won't fit on one page
 */
public class PdfPTableWriter {

    // Instance variables
    private PdfPTable table;
    private PdfWriter writer;
    private Document document;

    // List of how many columns per horizontal page
    private List numberOfColumnsPerPage;

    // List of how many rows per vertical page
    private List numberOfRowsPerPage;

    // Offsets if given
    private float widthOffset = 20;
    private float heightOffset = 70;

    /**
     * Class Constructor
     */
    public PdfPTableWriter(Document document, PdfWriter writer, PdfPTable table) {
        this.document = document;
        this.writer = writer;
        this.table = table;
        calculateColumns();
        calculateRows();
    }

    /**
     * Writes the table to the document
     */
    public void writeTable() throws DocumentException {
        // Begin at row 1 (row after the header)
        int rowBegin = 1;
        int rowEnd = 0;
        // Note the size of numberOfRowsPerPage is how many vertical
        // pages there are.
        Iterator rowsIter = numberOfRowsPerPage.iterator();
        while (rowsIter.hasNext()) {
            rowEnd = ((Integer) rowsIter.next()).intValue();
            writeSelectedRows(rowBegin, rowEnd);
            rowBegin = rowEnd;
        }
    }

    /**
     * Prints the Report's columns (splitting horizontally if necessary) and
     * subsequent rows
     * 
     * @param rowBegin
     * @param rowEnd
     * @throws DocumentException
     */
    private void writeSelectedRows(int rowBegin, int rowEnd) throws DocumentException {
        int colBegin = 0;
        int colEnd = 0;
        float pageHeight = document.getPageSize().getHeight() - heightOffset;
        PdfContentByte contentByte = writer.getDirectContent();
        Iterator columnsIter = numberOfColumnsPerPage.iterator();
        while (columnsIter.hasNext()) {
            colEnd = colBegin + ((Integer) columnsIter.next()).intValue();
            // Writer table header
            writeSelectedRows(colBegin, colEnd, 0, 1, widthOffset, pageHeight);
            // Writes selected rows to the document
            writeSelectedRows(colBegin, colEnd, rowBegin, rowEnd, widthOffset, pageHeight - table.getRowHeight(0) /*table.getHeaderHeight()*/);
            // Add a new page
            document.newPage();
            colBegin = colEnd;
        }
    }

    public int getTotalPages() {
        return numberOfColumnsPerPage.size() * numberOfRowsPerPage.size();
    }

    public void setHeightOffset(float heightOffset) {
        this.heightOffset = heightOffset;
    }

    public void setWidthOffset(float widthOffset) {
        this.widthOffset = widthOffset;
    }

    private void writeSelectedRows(int colBegin, int colEnd, int rowBegin, int rowEnd, float x, float y) {
        PdfContentByte cb = writer.getDirectContent();
        table.writeSelectedRows(colBegin, colEnd, rowBegin, rowEnd, x, y, cb);
    }

    private void calculateColumns() {
        numberOfColumnsPerPage = new ArrayList();
        float pageWidth = document.getPageSize().getWidth() - widthOffset;
        float[] widths = table.getAbsoluteWidths();
        if (table.getTotalWidth() > pageWidth) {
            // tmp variable for amount of total width thus far
            float tmp = 0f;
            // How many columns for this page
            int columnCount = 0;
            // Current page we're on
            int currentPage = 0;
            // Iterate through the column widths
            for (int i = 0; i < widths.length; i++) {
                // Add to the temporary total
                tmp += widths[i];
                // If this column will not fit on the page
                if (tmp > pageWidth) {
                    // Add the current column count to this page
                    numberOfColumnsPerPage.add(new Integer(columnCount));
                    // Since this column won't fit, the tmp variable should
                    // start off the next iteration
                    // as this column's width
                    tmp = widths[i];
                    // Set column count to 1, since we have moved this column to
                    // the next page
                    columnCount = 1;
                }
                // If this is will fit on the page
                else {
                    // Increase the column count
                    columnCount++;
                }
            }
            // Save the remaining columns
            numberOfColumnsPerPage.add(new Integer(columnCount));
        }

        // All the columns will fit on one horizontal page
        // Note: -1 means all the columns
        else {
            numberOfColumnsPerPage.add(new Integer(-1));
        }
    }

    private void calculateRows() {
        numberOfRowsPerPage = new ArrayList();
        float pageHeight = document.getPageSize().getHeight() - heightOffset - table.getRowHeight(0) /*table.getHeaderHeight()*/;
        // If the table won't fit on the first page
        if (table.getTotalHeight() > pageHeight /*table.getHeaderHeight()*/) {
            // Temp variables
            float tmp = 0f;
            // Determine the start and end rows for each page
            for (int i = 1; i < table.size(); i++) {
                // Add this row's height to the tmp total
                tmp += table.getRowHeight(i);
                if (tmp > pageHeight - (heightOffset/2)) {
                    // This row won't fit so end at previous row
                    numberOfRowsPerPage.add(new Integer(i - 1));
                    // Since this row won't fit, the tmp variable should start
                    // off the next iteration
                    // as this row's height
                    tmp = table.getRowHeight(i);
                }
            }
            // Last page always ends on totalRows
            numberOfRowsPerPage.add(new Integer(table.size()));
        }

        // All the rows will fit on one vertical page
        // Note: -1 means all the rows
        else {
            numberOfRowsPerPage.add(new Integer(-1));
        }
    }
}

答案 2 :(得分:0)

好吧,我会尽力给你一些回应。首先,正如@mkl所说,1.4.8是古代版本。查看http://sourceforge.net/projects/itext/files/iText/以获得更好的结果,最后一个版本是5.4.5。而且据我所知,没有办法将宽表分成两页。如果文档比页面“有点”宽 - 旋转页面,但如果你有许多不适合的列 - 你必须按照自己的方式去做,这可能会很痛苦。没有自动功能可以检查您的列是否包含太多文本且不适合页面。

希望这会对你有所帮助。