如何在下一页重复表格的最后5行?

时间:2014-03-03 17:37:26

标签: java pdf itext

我一直在寻找答案,但无法找到一个好的教程。我正在使用Java itext生成pdf。我有一张桌子,可以打印超过50行,大约2页。在继续打印列表之前,我需要将上一页的最后5行打印到下一页。

Example: row 31 row 32 row 33 row 34 row 35 row 36 --end of page 1-- row 32 row 33 row 34 row 35 row 36 row 37

关于如何做到这一点的任何想法?

Currently it prints like this: row 35 row 36 --end of page 1-- row 37 row 38

代码:(专注于启动循环,不要介意那些标题)

PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(97);
table.setWidths(new float[] {10, 45, 25, 25});

PdfPCell c1 = new PdfPCell(new Phrase("Logo", FontFactory.getFont(FontFactory.TIMES_ROMAN, 14)));
c1.setPadding(5);
c1.setHorizontalAlignment(Element.ALIGN_LEFT);
c1.setVerticalAlignment(Element.ALIGN_CENTER);
c1.setBorder(0);
c1.setColspan(4);
table.addCell(c1);

c1 = new PdfPCell(new Phrase("09/01/2013 - 09/15/2013", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
c1.setPadding(5);
c1.setHorizontalAlignment(Element.ALIGN_LEFT);
c1.setVerticalAlignment(Element.ALIGN_CENTER);
c1.setBorder(0);
c1.setColspan(4);
c1.setPaddingBottom(20);
table.addCell(c1);

//start header
c1 = new PdfPCell(new Phrase(" ", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
c1.setPaddingBottom(5);
c1.setHorizontalAlignment(Element.ALIGN_LEFT);
c1.setBackgroundColor(WebColors.getRGBColor("#99CCFF"));
c1.setBorder(1);
table.addCell(c1);

c1 = new PdfPCell(new Phrase("Name", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
c1.setPaddingBottom(5);
c1.setHorizontalAlignment(Element.ALIGN_LEFT);
c1.setBackgroundColor(WebColors.getRGBColor("#99CCFF"));
c1.setBorder(1);
table.addCell(c1);

c1 = new PdfPCell(new Phrase("Number", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
c1.setPaddingBottom(5);
c1.setHorizontalAlignment(Element.ALIGN_LEFT);
c1.setBackgroundColor(WebColors.getRGBColor("#99CCFF"));
c1.setBorder(1);
table.addCell(c1);

c1 = new PdfPCell(new Phrase("Amount", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
c1.setPaddingBottom(5);
c1.setHorizontalAlignment(Element.ALIGN_RIGHT);
c1.setBackgroundColor(WebColors.getRGBColor("#99CCFF"));
c1.setBorder(1);
table.addCell(c1);
//end header

//start for loop
for(int a=0; a<50; a++)
{
    int border=0;
    if(a%5==0)
    {border=1;}

    c1 = new PdfPCell(new Phrase((a+1)+"", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
    c1.setHorizontalAlignment(Element.ALIGN_LEFT);
    c1.setBorder(border);
    c1.setPaddingBottom(5);
    table.addCell(c1);

    c1 = new PdfPCell(new Phrase("Last Name, First Name", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
    c1.setHorizontalAlignment(Element.ALIGN_LEFT);
    c1.setBorder(border);
    c1.setPaddingBottom(5);
    table.addCell(c1);

    c1 = new PdfPCell(new Phrase("1", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
    c1.setHorizontalAlignment(Element.ALIGN_CENTER);
    c1.setBorder(border);
    c1.setPaddingBottom(5);
    table.addCell(c1);

    c1 = new PdfPCell(new Phrase("1", FontFactory.getFont(FontFactory.TIMES_ROMAN, 12)));
    c1.setHorizontalAlignment(Element.ALIGN_RIGHT);
    c1.setBorder(border);
    c1.setPaddingBottom(5);
    table.addCell(c1);


}
//end for loop

subCatPart.add(table);

2 个答案:

答案 0 :(得分:1)

使用document.add()无法实现此目的;相反,您需要使用writeSelectedRows()方法编写特定行。例如,参见RepeatLastRows方法。

在这个例子中,我有一个包含99行的表。如果我使用document.add()将此表添加到文档中,则需要3页,第三页只显示3行。您希望此页面显示5行,重复上一页的2行。

这是如何做到的,假设我们有一个边距为36pt的A4页面。这意味着可用表面测量523乘770 pt:

// we create a table that spans the width of the page and that has 99 rows
PdfPTable table = new PdfPTable(1);
table.setTotalWidth(523);
for (int i = 1; i < 100; i++)
    table.addCell("row " + i);

请注意,我设置了总宽度。如果在未指定宽度的情况下使用writeSelectedRows(),则会出现异常。

我们初始化一些参数:

PdfContentByte canvas = writer.getDirectContent();
int currentRowStart = 0;
int currentRow = 0;
int totalRows = table.getRows().size();

只要currentRow低于totalRows,我们就会创建一个循环:

while (true) {
    // available height of the page
    float available_height = 770;
    // how many rows fit the height?
    while (available_height > 0 && currentRow < totalRows) {
        available_height -= table.getRowHeight(currentRow++);
    }
    // we stop as soon as all the rows are counted
    if (currentRow == totalRows)
        break;
    // we draw part the rows that fit the page and start a new page
    table.writeSelectedRows(currentRowStart, --currentRow, 36, 806, canvas);
    document.newPage();
    currentRowStart = currentRow;
}

在这个循环中,我们已经填充了两个页面:一个显示第1行到第48行,另一个显示第49到96行。当我们退出循环时,currentRow为99且currentRowStart为96(这是第97行的行索引。这意味着仅显示行97,98和99。我们想要显示5行,因此我们相应地更改currentRow的值。

if (currentRow - currentRowStart < 5)
    currentRowStart = currentRow - 5;
table.writeSelectedRows(currentRowStart, currentRow, 36, 806, canvas);

请查看生成的PDF,您会看到第三页以第95行开头(第2页已经显示的一行)。

更新:我误解了这个问题,我认为只有在最后一页上有一些孤立的行时才需要重复这些行。实际要求是每次分割表时总是重复5行。

我稍微更新了我的原始示例。见RepeatLastRows2。您更改了currentRowStart的值,以便开始返回5行,但您忘记更新currentRow值。因此,您不会从可用高度中减去足够的空间。

如果只有5行(或更少)适合单个页面,请确保不要反复重复相同的5行(或ArrayIndexOutOfBoundsExceptions)。

答案 1 :(得分:0)

您可以使用最近引入的PdfPTableEventAfterSplit,这是在需要拆分表时触发的。它在呈现当前页面之后但在下一页面启动之前触发。您可以使用它来复制下一页要重复的行。

class RepeatSplitEvent extends PdfPTableEventForwarder {
    @Override
    public void afterSplitTable(PdfPTable table, PdfPRow startRow, int startIdx) {
        for (int i = startIdx - 5; i < startIdx; i++) {
            table.getRows().add(0, table.getRow(i));
        }
    }
}

// ...
PdfPTable table = new PdfPTable(4);
table.setTableEvent(new RepeatSplitEvent());
// ...