【问题标题】:How to span wide tables across multiple pages horizontally?如何水平跨越多个页面的宽表?
【发布时间】:2014-02-01 18:53:56
【问题描述】:

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

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

【问题讨论】:

  • 我不太了解你。 “拆分宽表”是什么意思?对我来说宽并不大。如果表格有很多行,您可以跨多个页面拆分。如果它不适合页面宽度......我不知道。请解释一下。
  • iText 版本 1.4.8 - 我怀疑人们可能有的所有想法都可以用那个古老的 iText 版本来实现。
  • iText 自动在页面之间拆分长表格(多行表格)。我需要别的东西。想象一个宽表 - 一个有 40 列的表。如果您尝试渲染它,即使您使用横向页面方向,每列的宽度也会变小。目标是垂直拆分表格,即对于适合页面的每组行,将前 20 列垂直放置在一个页面上,将其他 20 列放在下一页上。
  • 如何并行创建两个表,一个包含前 20 列,一个包含其余列,然后将它们一个接一个地添加到文档中?

标签: java pdf itext tabular


【解决方案1】:

请查看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 将继续绘制表格,即使这意味着某些内容超出了页面的可见区域。这意味着您在使用此方法时必须非常小心:您需要在添加表格之前计算行和列的宽度和高度,否则您最终可能会得到不可见的表格部分。

【讨论】:

    【解决方案2】:

    这是一个类的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));
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      希望对你有所帮助。

      【讨论】:

      • 我不介意升级 iText 或做一些手动工作。我只是看不到路径。当表格有 40 列或更多列时,横向页面方向根本没有帮助。我正在考虑以编程方式在两个真实的 20 列表之间拆分一个逻辑 40 列表,一个表用于列 1...20,另一个用于列 21...40,然后将它们一个接一个地添加到文档中。不幸的是,这种方法并没有真正的帮助,因为如果我的 40column 表有很多行,最终的布局会有点尴尬:表格左侧有很多页,右边有很多页
      猜你喜欢
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多