关于itextsharp:iText:我可以在渲染期间调整表格单元的高度吗?

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

我正在生成一个PdfPTable并将其添加到章节中,然后将该章节添加到我的文档中。我的表有多个单元格,其中RowSpan> 1,有时这些跨度跨越页面边界,当发生这种情况时,我希望跨度的单元格再次出现。换句话说,如果我的表格如下所示:

1
2
3
4
5
6
7
+------------------+------------------+
| Cell 1 RowSpan=1 | Cell 2 RowSpan=3 |
+------------------+------------------+
| Cell 3 RowSpan=1 |                  |
+------------------+------------------+
| Cell 4 RowSpan=1 |                  |
+------------------+------------------+

但是在打印时,第2行和第3行之间有一个分页符,我希望表格看起来像这样:

1
2
3
4
5
6
7
8
9
+--------+--------+
| Cell 1 | Cell 2 |
+--------+        |
| Cell 3 |        |
+--------+--------+
Page Break
+--------+--------+
| Cell 4 | Cell 2 |
+--------+--------+

这要归功于我在这里学到的技巧,我有一个实现IPdfPCellEvent的类,该类实例化并附加到RowSpan> 1的单元格上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();
        }
    }
}

如果CellLayout()被多次调用,则会发生后续调用,因为RowSpan已溢出到新页面上(我在上面描述的确切情况),因此我手动重新绘制了单元格文本。这很好。

除了。

如果我的单元格2比我的单元格1高:

1
2
3
4
5
6
+------------------+-------------------------+
| Cell 1 RowSpan=1 | Cell 2 Line 1 RowSpan=2 |
|                  | Cell 2 Line 2           |
+------------------+-------------------------+
| Cell 3 RowSpan=1 |                         |
+------------------+-------------------------+

表在这两行之间中断,我看到的是:

1
2
3
4
5
6
7
8
+--------+---------------+
| Cell 1 | Cell 2 Line 1 |
|        | Cell 2 Line 2 |
+--------+---------------+
Page Break
+--------+---------------+
| Cell 3 | Cell 2 Line 1 |
+--------+---------------+

因为,当然,该表不知道我要在第2行中绘制两行文本。

我可以将第2行设置为始终足够高以容纳两行,但是如果表恰好以这样的方式掉落,使得第1行和第2行之间没有分页符,则会在行中产生不必要的空白#2:

1
2
3
4
5
6
7
+--------+---------------+
| Cell 1 | Cell 2 Line 1 |
|        | Cell 2 Line 2 |
+--------|               |
| Cell 3 |               |
|        |               | <- un-necessary space
+--------+---------------+

我尝试添加一个实现IPdfPTableEvent的类并将其附加到我的文档中,但是看来在执行完所有布局后会调用TableLayout(),因此我没有机会潜入并调整行高。

我想我可以使用PdfPTable.KeepRowsTogether()来防止在行跨度中间出现分页符,但这不是首选格式。

当表格呈现在PDF文档中时,是否有办法"介入"表格的布局,以便我可以调整行的高度?

ps。我刚刚创建了PdfPTable的子类,在其中重写GetRowHeight(idx)并返回所需的行高。它对生成的PDF无效。


我想出的解决方案是非迭代的(请参阅@ChrisHaas的想法),但需要更多代码。 代码有点混乱(反映了我为弄清解决方案而进行的所有迭代),所以我不会全部上传,但是基本要点是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class TableRowInfo
{
    public int height;
}
public class TableEvent : IPdfPTableEventAfterSplit
{
    Dictionary<PdfPRow, TableRowInfo> m_rows = null;
    public bool LoadSpans(PdfPTable table)
    {
        // Fill in m_rows, mapping PdfPRow to information about the height
        // of cells in that row, keeping row-spanning in mind
    }
    void IPdfPTableEventAfterSplit.AfterSplitTable(PdfPTable table, PdfPRow rowToStartNextPage, int startIdx)
    {
        TableRowInfo rowInfo = m_rows[rowToStartNextPage];
        if (rowInfo.height > rowToStartNextPage.MaxHeights)
        {
            PdfPCell[] cells = rowToStartNextPage.GetCells();
            foreach (PdfPCell cell in cells)
            {
                if (cell != null)
                    cell.MinimumHeight = rowInfo.height;
            }
            rowToStartNextPage.MaxHeights = rowInfo.height;
        }
    }
}
PdfPTable table = new PdfPTable(...);
// Fill in the rows of the table here
table.TableEvent = new TableEvent();
table.TableEvent.LoadSpans(table);