< 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 讀書筆記。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM