天道酬勤

<<iText in Action 2nd>>4.4 (Adding a table at an absolute position)读书笔记

前言

在第二节中我们创建了大量high-level的对象,iText会自动对其布局。在第三节的时候我们学会了writing to direct content,然后使用ColumnText对象将high-levl和lowel-level对象组合起来使用。目前为止我们将PdfPTable对象当作high-level对象使用,因此在其被添加到Document时:单元格的文本内容会被添加到文本层(text layer),其它所有的边框,背景色,图片都添加到文本层的下面。但是我们也可以将PdfPTable添加到文本层的上面抑或是图形层的下面。

Working with WriteSelectedRows()

下图是2011年的日历,背景是一张图片,而在背景前面是一个绝对定位的表格。

PdfCander

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

假设一个表格的列太多了导致一页不能完全显示,这个时候我们就可以将表格在水平面上分隔,就如下图:

zhang

上图是一个表格,其内容是张艺谋导演的电影,表格总的宽度设置为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

好了直接上图和代码:

ColumnTable

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 读书笔记。

posted @ 2012-07-10 22:19  JulyLuo  阅读(2762)  评论(3编辑  收藏  举报