前言
在第二節中我們創建了大量high-level的對象,iText會自動對其布局。在第三節的時候我們學會了writing to direct content,然后使用ColumnText對象將high-levl和lowel-level對象組合起來使用。目前為止我們將PdfPTable對象當作high-level對象使用,因此在其被添加到Document時:單元格的文本內容會被添加到文本層(text layer),其它所有的邊框,背景色,圖片都添加到文本層的下面。但是我們也可以將PdfPTable添加到文本層的上面抑或是圖形層的下面。
Working with WriteSelectedRows()
下圖是2011年的日歷,背景是一張圖片,而在背景前面是一個絕對定位的表格。
listing 4.21 PdfCalendar.cs
PdfPTable table; Calendar calendar = CultureInfo.GetCultureInfo(LANGUAGE).Calendar; PdfContentByte canvas = writer.DirectContent; for (int month = 1; month <= 12; month++) { // draw the background DrawImageAndText(canvas, month.ToString().PadLeft(2, '0')); // create a table with 7 columns table = new PdfPTable(7); table.TotalWidth = 504; // add the name of the month table.DefaultCell.BackgroundColor = BaseColor.WHITE; DateTime dt = new DateTime(YEAR, month, 1); table.AddCell(GetMonthCell(dt)); int daysInMonth = DateTime.DaysInMonth(YEAR, month); int day = 0; int position = (int)calendar.GetDayOfWeek(dt); // add empty cells for (int j = 0; j < position; j++) { table.AddCell(""); } // add cells for each day do { DateTime oneDt = dt.AddDays(day); day++; table.AddCell(GetDayCell(calendar, oneDt)); } while (day < daysInMonth); // complete the table table.CompleteRow(); // write the table to an absolute position table.WriteSelectedRows(0, -1, 169, table.TotalHeight + 18, canvas); document.NewPage(); }
在我們將table絕對定位時一定要設置表格總的寬度(TotalWidth),而且我們也不需要將寬度鎖定,因為iText會忽視WidthPercentage的屬性(這個屬性只有在通過Documnet.Add方法添加時才有效)。表格的絕對定位是通過WriteSelectedRows方法實現的,現在我們討論下此方法的參數。
SELECTING THE ROWS AND THE TABLE POSITION
方法的前兩個參數是表格的起始和結束列,0到-1表示添加所有的列,其中-1表示所有剩余的列。接下來的兩個參數是表格絕對定位的左上角座標,因為希望表格不要離頁面的下邊距太近,我們在表格的高度上添加了18pt。最后一個參數就是要添加的PdfContentByte對象。
CONTENT CANVASES
除了單個的PdfContentByte對象,WriteSelectedRows方法還接受4個PdfContentByte對象組合的一個數組,其中每個PdfContentByte對象都有一個特定的名稱和目的:
- PdfPTable.BASECANVAS----添加到這里的內容會處於表格下面
- PdfPTable.BACKGROUNDCANVAS----背景色的層
- PdfPTable.LINECANVAS----線的層
- PdfPTable.TEXTCANVAS----表格中文本的層,其會位於表格上面
如果只是傳入一個PdfContentByte對象,則文本位於線上面,線位於背景色上面,背景色位於BaseCanvas上面。
SPLITTING A PDFPTABLE VERTICALLY
假設一個表格的列太多了導致一頁不能完全顯示,這個時候我們就可以將表格在水平面上分隔,就如下圖:
上圖是一個表格,其內容是張藝謀導演的電影,表格總的寬度設置為600pt,但頁面可用的寬度只有595pt。因此使用了兩次WriteSelectedRows方法來實現,具體參考以下代碼:
listing 4.22 Zhang.cs
// Create a table and fill it with movies List<Movie> movies = PojoFactory.GetMovies(conn, 3); PdfPTable table = new PdfPTable(new float[] { 1, 5, 5, 1 }); foreach (Movie movie in movies) { table.AddCell(movie.Year.ToString()); table.AddCell(movie.Title); table.AddCell(movie.OriginalTitle); table.AddCell(movie.Duration.ToString()); } // set the total width of the table table.TotalWidth = 600; PdfContentByte canvas = writer.DirectContent; // draw the first three columns on one page table.WriteSelectedRows(0, 2, 0, -1, 236, 806, canvas); document.NewPage(); // draw the next three columns on the next page table.WriteSelectedRows(2, -1, 0, -1, 36, 806, canvas);
在第一次調用WriteSelectedRows方法時我們將前兩列添加到一頁中,其它的列添加到下一頁中。通過WriteSelectedRows方法可以將表格絕對定位,但還有一種絕對定位的方法:將PdfPTable對象包裹在ColumnText對象中。
Wrapping tables in columns
好了直接上圖和代碼:
listing 4.23 ColumnTable.cs
ColumnText column = new ColumnText(writer.DirectContent); List<DateTime> days = PojoFactory.GetDays(conn); float[,] x ={ { document .Left ,document .Left +380}, { document .Right -380,document .Right }}; foreach (DateTime day in days) { // add content to the column column.AddElement(GetTable(conn, day)); int count = 0; float height = 0; int status = ColumnText.NO_MORE_COLUMN; // render the column as long as it has content while (ColumnText.HasMoreText(status)) { // add the top-level header to each new page if (count == 0) { height = AddHeaderTable(document, day, writer.PageNumber); } // set the dimensions of the current column column.SetSimpleColumn(x[count, 0], document.Bottom, x[count, 1], document.Top - height - 10); // render as much content as possible status = column.Go(); // go to a new page if you've reached the last column if (++count > 1) { count = 0; document.NewPage(); } } document.NewPage(); }
這里使用的是ColumnText對象的一些屬性,比較簡單就不詳細解釋。
總結
表格的絕對定位這里使用了兩種方式:WriteSelectedRows方法和ColumnText對象,這兩種方式都設計一些low-level的操作。這里第四節的內容就完全結束了,但對於PdfPTable和PdfPCell的討論還要繼續,下一節中我們會使用表格和單元格的事件進行更加完美的布局,最后是代碼下載。
同步
此文章已同步到目錄索引:iText in Action 2nd 讀書筆記。