<<iText in Action 2nd>4.3节(Dealing with large tables)读书笔记

前言

在上一节中,通过listing 4.16产生的表格拥有一个头,表头中显示的为日期。如果我们仔细观察此PDF的话你会发现基本上每一部电影的信息都会超过一页,表格中数据被分割的不错,但是表头却消失了。在这一节中我们会fix这个问题,而且还会为表格添加footer。

Repeating headers and footers

好了直接上效果图:

HeaderFooter1

上图是具体一天的电影播放信息,日期显示在第一行,第二行包括一些列的描述信息:Location,Time,Run Length等,同样的信息还被加入到footer中。为了实现上图的效果我们需要添加三列:背景为黑色且有日期的一列,背景为灰色的二列(一列添加到header,一列添加到footer)。具体参考以下代码:

listing 4.18 HeaderFooter1.cs

PdfPCell cell = new PdfPCell(new Phrase(day.ToString("yyyy-MM-dd"), f));
cell.BackgroundColor = BaseColor.BLACK;
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.Colspan = 7;
table.AddCell(cell);
// Add the second header row twice
table.DefaultCell.BackgroundColor = BaseColor.LIGHT_GRAY;
for (int i = 0; i < 2; i++)
{
    table.AddCell("Location");
    table.AddCell("Time");
    table.AddCell("Run Length");
    table.AddCell("Title");
    table.AddCell("Year");
    table.AddCell("Directors");
    table.AddCell("Countries");
}

table.DefaultCell.BackgroundColor = null;
// There are three special rows
table.HeaderRows = 3;
// One of them is a footer
table.FooterRows = 1;

以上代码看起来有点奇怪:我们在还没有添加内容时就将footer添加进去了。不过这是iText内部设置的:首先通过HeaderRows属性告诉iText有三个特殊的列,然后通过FooterRows属性说明其中一个为footer列。这样前两列就被先添加进去,然后是具体的内容,但需要新的一页或者没有数据时,第三列也就是footer列就会被添加。表格跨页显示时表头也会被重复,footer也会在表格的末端重复,但如果设置SkipLastFooter为true就footer列就不会被添加。重复的footer列有一个好处就是可以提示我们:表格会在下一页继续显示。和SkipLastFooter属性对应的为SkipFirstHeader,将其设置为true也可以提示我们:表格在前一样也有数据。

Splitting tables

当表格中的一列不能在一页中完全填充时就有两个选择:在新的一页开始这一列或者尽可能多在当前页中的列中添加数据,然后将剩下的数据添加到下一页中。这两种方式在iText中都是支持的,具体看下图:

SpliteTable

在上图的上部大家可以看到,当Terminator2这一列不能在前一页完全填充时,这一列就会在下一页中被完全添加,这也是默认的行为。在图的下部Termianator2的数据被分布在两页中,具体的实现代码很简单:

listing 4.19 HeaderFooter2.cs

PdfPTable table = GetTable(conn, day);
table.SplitLate = true;
document.Add(table);

Memory management for LargeElement implementations

在第二节我们学习实现了ILargElement的Chapter和Section对象,这一节中PdfPTable也实现了此接口。这些对象会在被添加到文档之前,我们一般会往其添加大量的内容,相应也会消耗大量内存。一般当我们将一些对象添加到Document时,这些对象就可以被GC回收,但类似PdfPTable和Chapter对象我们只能在完成之后才能将其添加到Document中。因此我们希望有一个完善的解决方案:在这些对象没有被添加到Document之前我们可以将部分内容写入到PdfWriter和相应的输出流中以便减少内存消耗,而且我们希望这个过程没有副作用(side effects),不会影响到PdfPTable的header,footer以及Chapter对象的标题,缩进等。ILargeElement就是为了解决这个问题而创建的。以下为ILargeElement接口:

public interface ILargeElement : IElement {
       
       /**
       * If you invoke setCompleted(false), you indicate that the content
       * of the object isn't complete yet; it can be added to the document
       * partially, but more will follow. If you invoke setCompleted(true),
       * you indicate that you won't add any more data to the object.
       * @since   iText 2.0.8
       * @param   complete    false if you'll be adding more data after
       *                      adding the object to the document.
       */
       bool ElementComplete {
           get;
           set;
       }
       
       /**
       * Flushes the content that has been added.
       */
       void FlushContent();
   }

其中FlushContent方法是有内部管理,我们只需要设置ElementComplete属性,具体代码如下:

listing 4.20 MemoryTests.cs

// Create a table with 2 columns
PdfPTable table = new PdfPTable(new float[] {1, 7});
// Mark the table as not complete
if(test)
{
    table.ElementComplete = false;
}


// add information about a movie
foreach (var movie in movies)
{
    ……// insert a checkpoint every 10 movies
    if(count ++%10==0 )
    {
        // add the incomplete table to the document
        if(test)
        {
            document.Add(table);
        }
     }
}

// Mark the table as complete
if(test)
{
    table.ElementComplete = true;
}
// add the table to the document
document.Add(table);

在以上代码中,实现设置表格的ElementComplete属性为false,然后就可以在表格还没有完全构建完毕之前将其添加到文档中,最后表格构建完毕时设置ElementComplete属性为true,最后再次添加到文档中即可。书中的列子还详细的写了使用ILargeElement接口和不使用的内存使用,这里我就没有写了,各位那个老鸟就帮忙写个。

总结

这一节主要是对大数据量表格的处理,如重复的header和footer,最后一列的处理方式,最后就是内存的使用。看起来比较复杂但iText已经封装的很好,写代码时只要设置几个属性即可。最后是代码下载

同步

此文章已同步到目录索引:iText in Action 2nd 读书笔记。

原文地址:https://www.cnblogs.com/julyluo/p/2583555.html