Betty Crokker February 2016

iText: Can I adjust the height of a table cell during rendering?

I am generating a PdfPTable and adding it to a Chapter, and then adding the Chapter to my Document. My table has several cells where RowSpan > 1, and sometimes those spans cross page boundaries, and when that happens I want the spanned cell to appear again. In other words, if my table looks like this:

+------------------+------------------+
| Cell 1 RowSpan=1 | Cell 2 RowSpan=3 |
+------------------+------------------+
| Cell 3 RowSpan=1 |                  |
+------------------+------------------+
| Cell 4 RowSpan=1 |                  |
+------------------+------------------+

but when printed, there's a page break between rows 2 and 3, I want the table to look like this:

+--------+--------+
| Cell 1 | Cell 2 |
+--------+        |
| Cell 3 |        |
+--------+--------+
Page Break
+--------+--------+
| Cell 4 | Cell 2 |
+--------+--------+

This is working thanks to a trick I learned here, I have a class which implements IPdfPCellEvent which I instantiate and attach to cells that have RowSpan > 1:

public class CellEvent : IPdfPCellEvent
{
    Phrase m_phrase;
    bool m_first = true;

    public CellEvent(Phrase phrase)
    {
        m_phrase = phrase;
    }

    void IPdfPCellEvent.CellLayout(PdfPCell cell, Rectangle r, PdfContentByte[] canvases)
    {
        if (m_first)
            m_first = false;
        else
        {
            ColumnText ct = cell.Column;
            ct.Canvases = canvases;
            m_phrase.Leading = m_phrase.Font.Size;
            ct.AddElement(m_phrase);
            ct.Go();
        }
    }
}

If the CellLayout() gets called more than once, the subsequent calls are happening because the RowSpan has spilled onto a new page (the exact situation I described above) and so I manually re-draw the cell text. This works great.

Except.

If my cell 2 is taller than my cell 1:

+------------------+--------------        

Answers


Betty Crokker February 2016

The solution I came up with, is non-iterative (see @ChrisHaas' idea in the comments) but took a bit more code. It's more code than I want to upload here, but the basic idea is this:

  • I added a TableEvent to my table.
  • Once I have added all the cells to my table, before I add the table to my document and thus long before I start actually rendering the table, I calculate how tall each row needs to be, based on the cells in that row (including any cells that are rowspanned from a previous row) and store that information.
  • During rendering, every time IPdfPTableEvent.TableLayout() gets called, I keep track of how many rows have been rendered thus far. Based on that information, I know which row will appear at the top of the next page.
  • If the row height (as reported by table.GetRowHeight()) for the first row on the top of the next page is insufficient for the cells in that row (including rowspanned cells), I find a cell in that row that is not rowspanned and set its MinimumHeight to the row height I know is actually required.

Post Status

Asked in February 2016
Viewed 1,186 times
Voted 10
Answered 1 times

Search




Leave an answer