Constructing tables (iText 5)

iText’s table functionality has evolved from a very low-level class in the early versions of iText to the twin classes Table and PdfTable in iText 0.30 (2000). These classes were useful, but they had some flaws. It was hard to fine-tune them due to design decisions made by the iText developers; that is, by me. Developers wanted to define how to split the table upon a page break, to control the way borders are drawn, and so on. The PdfPTable class, introduced by the codeveloper of iText, Paulo Soares, solved this problem.

The Table and PdfTable classes were removed in iText 5 (2009). So were Simple-Table and SimpleCell, two other table classes discussed in the first edition of iText in Action. Only PdfPTable and PdfPCell remain. They will be discussed in this topic.

Your first PdfPTable

Suppose that you need to create a simple table that looks like figure 4.1. The code to generate this kind of table is pretty simple.

Listing 4.1 MyFirstTable.java

Listing 4.1 MyFirstTable.java

When you create a PdfPTable, you always need to pass the number of columns to the constructor. Creating a table with zero columns results in a RuntimeException. You can add different objects to a PdfPTable object using the addCell() method.


AUTOMATIC CREATION OF ROWS

There’s a PdfPRow object in the com.itextpdf.text.pdf package, but you aren’t supposed to address it directly. iText uses this class internally to store the cells that belong to the same row.

Your first PdfPTable

Figure 4.1 Your first PdfPTable

In listing 4.1, the table has three columns O. After adding the first cell with column span 3 C, the first row is full. The next cell is added to a second row that is created automatically by iText. This cell has to span 2 rows ©, so a third row is created, of which the first cell is reserved. Four more cells are then added ©; the first pair completes the second row; the second pair completes the third row.

NOTE When you add a PdfPTable to a Document, only complete rows are added. If you have a table with three columns and your final row has only two cells, the row won’t be added unless you use the method PdfPTable. completeRow() .

You don’t have to worry about creating rows; iText creates them for you. Just make sure you’re adding the correct number of cells.

PdfPTable properties

We’ll talk about cells and cell properties such as text alignment, spacing, and borders in the next section. First, let’s take a look at the properties of the table: the width of the table and its columns, the spacing before and after the table, and the alignment of the table.

The default width of a table is 80 percent of the available width. Let’s do the math for the table created by listing 4.1. The width of the page is 595 pt minus the margins, which are 36 pt. Eighty percent of this width is (595 – (2 * 36)) * 0.80, which amounts to 418.4 pt.

TABLE WIDTH

Each PdfPTable keeps two values for the width:

■ widthPercentage—A percentage of the available width

■ totalWidth—The absolute width expressed in user space units

When you add a PdfPTable to a Document, iText looks at one of these values, ignoring the other, depending on the value of lockedWidth. If this value is true, the table will have a fixed width, as defined by the totalWidth variable. By default, the value is false, and the exact width of the table will depend on the width available on the page or the width of the ColumnText object to which it’s added. The default width of the columns is equal to the width of the table divided by the number of columns.

FAQ Is it possible to have the column width change dynamically based on the content of the cells? PDF isn’t HTML, and a PdfPTable is completely different from an HTML table rendered in a browser; iText can’t calculate column widths based on the content of the columns. The result would depend on too many design decisions and wouldn’t always correspond to what a developer expects. It’s better to have the developer define the widths.

You could say that each column has a relative width equal to 1. You can change this by defining new relative widths, or by setting absolute widths for the columns.

RELATIVE COLUMN WIDTHS

Figure 4.2 shows five tables that look identical, but the widths of the table and columns were changed in five different ways.

In the first three tables you define the column widths using relative values: new int[] {2, 1, 1} or new float{2, 1, 1}. This means that you want to divide the width of the table into four parts (2 + 1 + 1): two parts for the first column, one part for columns two and three.

Listing 4.2 ColumnWidths.java

Listing 4.2 ColumnWidths.java

Changing the widths of tables and columns

Figure 4.2 Changing the widths of tables and columns

Suppose you want a table with a width of 288 pt instead of 523 pt. You could compute the width percentage like this: (288 / 523) * 100 = 55.067. Or you could use the methods setTotalWidth() and setLockedWidth() instead of setWidthPercentage(), which is easier, because you can avoid the math. Listing 4.2 also demonstrates the use of an alternative constructor: instead of creating a PdfPTable with an int defining the number of columns, you pass the widths array as a parameter for the constructor.

ABSOLUTE COLUMN WIDTHS

The last two tables in figure 4.2 are created by code which defines absolute widths for the columns instead of for the whole table. This can be done in two different ways, both shown in this listing.

Listing 4.3 ColumnWidths.java

Listing 4.3 ColumnWidths.java

The first method—computing the width percentages—isn’t ideal. It will only work if you know the available width in advance. In listing 4.3, you pass a Rectangle object that represents the page size minus the margins.

It’s better to use setTotalWidth() with an array of float values as the parameter, then set the locked width to true.

SPACING BEFORE AND AFTER A PDFPTABLE

The five tables from listings 4.2 and 4.3 are added to the Document using this code.

Listing 4.4 ColumnWidths.java

Listing 4.4 ColumnWidths.javaListing 4.4 ColumnWidths.java

If you don’t provide any extra spacing, it’s hard to distinguish the different tables. This can be an advantage! You can create a structure that looks as if it’s one big table by adding a series of smaller, separate tables that are glued to each other.

TABLE ALIGNMENT

In figure 4.3, three tables were added after each other without extra spacing, but the alignment of the tables was changed in between.

Three tables with different alignments

Figure 4.3 Three tables with different alignments

The tables in figures 4.1 and 4.2 were centered; that’s the default alignment. You can change the alignment with the setHorizontalAlignment() method.

Listing 4.5 TableAlignment.java

Listing 4.5 TableAlignment.java

You’ve now played around with your first table; it’s time to pick up the thread started in the previous examples and return to the movie database.

Next post:

Previous post: