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

Posted

技术标签:

【中文标题】iText:我可以在渲染期间调整表格单元格的高度吗?【英文标题】:iText: Can I adjust the height of a table cell during rendering? 【发布时间】:2016-05-18 13:43:20 【问题描述】:

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

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

但打印时,第 2 行和第 3 行之间有一个分页符,我希望表格如下所示:

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

这要归功于我在这里学到的一个技巧,我有一个实现 IPdfPCellEvent 的类,我将其实例化并附加到 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();
        
    

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

除了。

如果我的 2 号牢房比 1 号牢房高:

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

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

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

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

我可以将第 2 行设置为始终足够高以容纳两行,但是如果表格恰好落在第 1 行和第 2 行之间没有分页符的情况下,则会生成不必要的白色第 2 行的空格:

+--------+---------------+
| Cell 1 | Cell 2 Line 1 |
|        | Cell 2 Line 2 |
+--------|               |
| Cell 3 |               |
|        |               | <- un-necessary space
+--------+---------------+

我尝试添加一个实现 IPdfPTableEvent 的类并将其附加到我的文档中,但似乎在执行所有布局之后调用了 TableLayout(),所以我没有机会潜入并调整行高.

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

有没有办法“参与”表格的布局,因为它正在呈现到 PDF 文档中,以便我可以调整行的高度?

附言我刚刚创建了 PdfPTable 的一个子类,在其中覆盖 GetRowHeight(idx) 并返回我想要的行高。它对生成的 PDF 没有影响。

【问题讨论】:

我上次接触 itext 已经有好几年了,但这听起来很熟悉。您是否尝试过将单元格 2 上的 PdfPCell.Header 设置为 true 我之前没有注意到... PdfPCell 有一个 AddHeader() 函数和一个只读 Headers 属性。我得研究一下它们是如何工作的...... 我不知道 PdfPHeaderCell 类的作用,当我创建一个并将其添加到我的单元格时,生成的 PDF 没有任何区别,而且我找不到任何文档。 @BettyCrokker,与你的问题无关,但你在这里问了很多关于 iText 的问题,你有时甚至难倒我!我真的很好奇你在那边煮什么! (我知道你可能无法告诉任何人,但我还是很好奇!) 无论如何,如果我理解你想要做的事情,我认为你唯一的选择是运行表创建两次,一次是为了弄清楚在它发生之前要做什么,一次是实际做它。在预运行(到具有相同页面尺寸的 MemoryStream 某处)中,您需要使用 IPdfPTableEventIPdfPCellEvent “记录”事物,然后使用 IPdfPTableEventSplit 或 @ “回放”它们987654333@. 【参考方案1】:

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

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);

【讨论】:

你能发布一些代码吗?我有同样的问题,不知道如何根据您的指示解决它。 我已经更新了我的回复,所以它是实际的代码,而不仅仅是谈论代码,希望这会让你朝着正确的方向前进。

以上是关于iText:我可以在渲染期间调整表格单元格的高度吗?的主要内容,如果未能解决你的问题,请参考以下文章

自动调整大小(动态高度)表格视图单元格的问题

涉及行跨度时,根据内容自动调整 HTML 表格单元格的高度

从自定义表格视图单元格类加载时如何调整单元格的高度?

我可以使用情节提要根据屏幕尺寸调整静态表格视图的大小吗?

仅针对一种原型单元格的自动表格视图单元格高度

具有动态调整单元格的可折叠表格视图