cobaltduck
cobaltduck

Reputation: 1598

iText PdfPTableEventForwarder not getting called when expected,

I will freely admit this is probably a duplicate of this, but there has been no answer there and I think I can add more info.

Using iText 5.5.0

What I need: A zebra-striped table where there is not a top/bottom border between cells, but there is a bottom border to the table itself, or whenever the table is split over multiple pages. I have a small snip here from a test run using "lorem ipsum" and other arbitrary data. I partially cut off the footer that says "Page 1 of 2" but this table does have additional rows that continue on page 2. I want this table to look more or less as it is, with the addition of a bottom border on the last row of the page.

enter image description here

I am trying to implement a PdfPTableEventForwarder via an anonymous inner class. I have a method that looks like this:

public PdfPTable createStandardTable(int columnCount, int headerRows) {
    PdfPTableEventForwarder tableEvent = new PdfPTableEventForwarder()
    {
        // begin another anonymous inner class extends PdfPTableEventForwarder
        @Override
        public void splitTable(PdfPTable table) {
            PdfPRow lastRow = table.getRow(table.getLastCompletedRowIndex());
            for (PdfPCell cell : lastRow.getCells()) {
                cell.setBorder(Rectangle.LEFT + Rectangle.RIGHT + Rectangle.BOTTOM);
            }
        }
        // end anonymous inner class extends PdfPTableEventForwarder
    };

    PdfPTable table = new PdfPTable(columnCount);
    table.setSpacingBefore(TABLE_SPACING);
    table.setSpacingAfter(TABLE_SPACING);
    table.setWidthPercentage(TABLE_WIDTH_PERCENT);
    table.setHeaderRows(headerRows);
    table.setTableEvent(tableEvent);
    return table;
}

And elsewhere I create my table like so:

// Details of code to create document and headers not shown
PdfPTable table = createStandardTable(12, 2);
// Details of code to build table not shown, but includes cell.setBorder(Rectangle.LEFT + Rectangle.RIGHT)
document.add(table);

I have run this in debugger with a break point at the first line inside splitTable and find that the event is only called once. I would expect it to call twice: first when page 1 ends and page 2 is beginning, second when the table is complete. Further, I have 30 rows in this table plus 2 header rows: 25 rows fit on page 1 with the header, the last five rows are on page 2. The debugger tells me that table.getLastCompletedRowIndex() evaluates to 32, not to 27 as expected at the end of page 1.

Indeed, the final result saved to my file has a bottom border on the last row on page 2, but not one on page 1. Neither one had a border prior to adding the PdfPTableEventForwarder.

Upvotes: 0

Views: 578

Answers (1)

Bruno Lowagie
Bruno Lowagie

Reputation: 77528

  • When you have a table with 10 rows and you split one row, you have a total number of 11 rows. That explains your confusion about the row count.
  • I don't understand why you use the PdfPTableEventForwarder when you only need one event. PdfPTableEventForwarder is used when you have a series of PdfPTable events.
  • Changing the cells in table or cell events is not correct. This will never work. When an event is triggered, the cell has already been rendered. If you want to draw a bottom border, draw a bottom border in a sequence of lineTo(), moveTo() and stroke() commands using the coordinates handed to you in the tableLayout() method of your PdfPTableEvent implementation.

An example that is different from what you need, but in a way similar can be found here: PressPreviews.java. No before or after split is needed, you just need the basic PdfPTableEvent interface and a tableLayout() method that looks like this.

public void tableLayout(PdfPTable table, float[][] width, float[] height,
        int headerRows, int rowStart, PdfContentByte[] canvas) {
    float widths[] = width[0];
    float x1 = widths[0];
    float x2 = widths[widths.length - 1];
    float y = height[height.length - 1];
    PdfContentByte cb = canvas[PdfPTable.LINECANVAS];
    cb.moveTo(x1, y);
    cb.lineTo(x2, y);
    cb.stroke();
}

I could be mistaken regarding the y value, but I hope you get the general idea.

Upvotes: 2

Related Questions