Changing the properties of a cell Part 1 (iText 5)

PdfPCell extends Rectangle, inheriting a plethora of methods to change the way borders are drawn and backgrounds are painted. We’ll discuss these methods later on. First, we’ll focus on the content of a PdfPCell.

Internally, PdfPCell content is kept inside a ColumnText object. The mechanics of a PdfPCell are easy to understand if you know how the ColumnText object works. If you skipped topic 3 because you were eager to know more about tables, please return to section 3.3 before reading about adding cells in text or composite mode.

PdfPCell in text mode

In this subsection, you’re going to create tables with content that can be expressed as Chunk or Phrase objects. An example of such a table is shown in figure 4.4.

Cells in text mode

Figure 4.4 Cells in text mode

You won’t use any Paragraph, List, or Image objects here. You’ll work in text mode, and therefore define the alignment and leading of the text using methods of the Pdf-PCell class.


COLSPAN, ROWSPAN, AND THE ALIGNMENT OF A CELL

You can experiment with colspan, rowspan, and different alignment methods.

Listing 4.6 MovieTextMode.java

Listing 4.6 MovieTextMode.javaListing 4.6 MovieTextMode.java

In listing 4.6, cells are added to the table in two ways.

■ With a PdfPCell object—You create a PdfPCell using a Phrase as a parameter, and add it to the table with the addCell() method. Before adding the cell, you use methods such as setHorizontalAlignment(), setVerticalAlignment(), and so on, to change the properties of the PdfPCell.

■ Without a PdfPCell object—You add a String or a Phrase object straight to the table with addCell(), using the properties of the default cell. The default cell is a special PdfPCell instance owned by the PdfPTable object. It can be accessed with the getDefaultCell() method.

The possible values for the setHorizontalAlignment() method are the same ones you used to set the alignment of the ColumnText object in the previous topic. The possible values for setVerticalAlignment() are Element.ALIGN_TOP, Element. ALIGN_MIDDLE,and Element.ALIGN_BOTTOM.

Different spacing in cells

Figure 4.5 Different spacing in cells

Just as with ColumnText, you can use the setIndent() method to define an indentation for the first line of a paragraph in the cell, setFollowingIndent() to specify the indentation of the first line of the paragraphs following the first paragraph, and set-RightIndent() to change the indentation to the right. Finally, there’s also a set-SpaceCharRatio() to change the ratio of the word spacing if you set the alignment to Element.

ALIGN_JUSTIFIED.

In the next example, you’ll experiment with the leading and the padding of a cell.

SPACING IN CELLS

The cells in the right column of the table shown in figure 4.5 have different leading or padding. Observe that the default leading of the content of a cell in text mode is equal to the font size. Internally, the leading is set like this:

tmp17C162_thumb

This is different from the default leading of a Phrase object outside a PdfPCell.

You can change the leading with the same setLeading() methods you’ve used for ColumnText; listing 4.7 is the code that produced the first five rows in figure 4.5. Note that setting the leading to 0 isn’t advised! The text will be added outside the cell, and if the content is split into multiple lines, they will overlap, resulting in illegible gibberish.

Listing 4.7 Spacing.java

Listing 4.7 Spacing.javaListing 4.7 Spacing.java

The default padding of a PdfPCell is 2 pt, and the setPadding() method can be used to change the default. Rows 6-8 in figure 4.5 are produced with the code in the following listing. Observe that you can differentiate: you can set different values for the top, bottom, left, and right padding.

Listing 4.8 Spacing.java

Listing 4.8 Spacing.java

Note that setPadding() creates a behavior that is similar to what happens if you use the cellpadding attribute of a <table> tag in an HTML table. There is no equivalent of the cellspacing attribute, but in topic 5 you’ll mimic that behavior using cell events.

You can adjust the padding depending on the ascender of the first line in the cell. The bottom padding can be adapted to the descender of the last line. By tweaking the boolean values of the setUseAscender() and setUseDescender() methods, you can create rows 9 to 12 in figure 4.5. This listing refers only to row 12.

Listing 4.9 Spacing.java

Listing 4.9 Spacing.java

Remember that you have measured text in the previous topic: the ascender was the space needed above the baseline; the descender was the space needed below the baseline.

Changing the leading and padding and using the ascender and descender have an impact on the height of a cell and, by extension, on the height of a row.

ROW HEIGHT

The height of a row is a value that needs to be computed, but iText doesn’t always have sufficient data to do the math.

Listing 4.10 TableHeight.java

Listing 4.10 TableHeight.java

In this example, the height of the table is 0 pt before and 48 pt after you add it to the Document. That’s normal: the height of a table can’t be computed before iText knows its width. The same table with a fixed width of 50 pt has a height of 192 pt. Due to this fixed width, which is much smaller than 80 percent of the available page width, the content in the cells has to be wrapped. This results in a larger table and cell height.

You could tell iText not to wrap the content with the setNoWrap(true) method, but I wouldn’t advise this. Unwrapped text risks exceeding the borders of the table and overlapping with the content of the next cell, or even, as shown in figure 4.6, going outside the page boundaries.

If you don’t like the calculated height, you can use setFixedHeight() to define the height yourself. Rows 3-6 in figure 4.6 are created with listing 4.11. Paragraph p contains the String "Dr. iText or: How I Learned to Stop Worrying and Love PDF." It is added to the table twice: once to a cell with a fixed height of 72 pt, and once to a cell with a fixed height of 36 pt.

Different row height methods for cells and tables

Figure 4.6 Different row height methods for cells and tables

A height of 36 pt isn’t enough, and the words "and Love PDF" aren’t shown. To put it in the terminology we used in topic 3, the go() method of the internal Column-Text method was invoked, and the content didn’t fit the rectangle. That content is never added to the table! Use this method only if you know for sure the content will fit the cell, or if it’s OK for your application to reduce the lines that are printed.

To assure a certain cell height, without losing any content, you can use the setMin-imumHeight() method. If the text fits the rectangle, the height will be equal to the desired height; if the text doesn’t fit, it will be larger.

Listing 4.11 CellHeights.java

Listing 4.11 CellHeights.javaListing 4.11 CellHeights.java

Note that the height of the final row is extended to the bottom margin of the page in figure 4.6. This isn’t a cell property; it’s something that has to be defined at the table level with the setExtendLastRow() method.

NOTE The setExtendLastRow() method exists in two versions. In listing 4.11, you use one Boolean to tell iText whether the row should be extended (true) or not (false). With a second Boolean, you can indicate whether the final row of the table has to be extended if the table is split and distributed over different pages.

So far, you’ve been working in text mode, but except for the leading, the horizontal alignment, and the indentation, the cell properties we’ve discussed are also valid in composite mode: cell height, padding, and so on. The same goes for the properties that are inherited from the Rectangle class.

ROTATION, BACKGROUND COLOR, BORDERS, AND BORDER COLORS

You can rotate the content of a cell with the setRotation() method. Just like with images, the rotation is defined counterclockwise. The answer to the questions, "What is horizontal?" and "What is vertical?" is affected by the rotation angle. This matters when setting the alignment. The word "GRAY" in the second row of figure 4.7 is centered horizontally, but not using the setHorizontalAlignment() method. Instead, it’s done by using setVerticalAlignment() with the parameter Element.

ALIGN_MIDDLE.

The first thing that jumps to the eye when looking at figure 4.7 is the fact that it’s more colorful than the previous table examples. The background color of the cells in the first row is changed with the setBackground() method. The setGrayFill() method changed the backgrounds of the cells in the second row. Note that the borders are different because the setBorder() method was used. Take a look at the next bit of code, which created some of the cells in figure 4.7, to discover more new Rectangle methods that can be used to change the properties of a cell.

Cells and rotation, background color, borders, and border colors

Figure 4.7 Cells and rotation, background color, borders, and border colors

Listing 4.12 RotationAndColors.java

Listing 4.12 RotationAndColors.java

Rectangle.NO_BORDER (which removes the border) is one possible value that can be used for the setBorder() method. To define a top, bottom, left, and right borders, you need Rectangle.TOP, Rectangle.BOTTOM, Rectangle.LEFT, and Rectangle.RIGHT. You’ll probably remember from topic 2, when we discussed the borders of the Image objects, that Rectangle.BOX is shorthand for the combination of the four borders. Rectangle.BOX is the default value for cell borders.

In listing 4.12, you use setUseBorderPadding(true) O- This adapts the padding to take the border width into account. Otherwise the border could overlap the content of the cell. This problem is demonstrated in the second cell of row 3 in figure 4.7.

The border width can be set with the setBorderWidth() method, but there are variations for every side of the border. The same goes for the setBorderColor() method. This is demonstrated in the next listing, which is responsible for drawing two more cells in figure 4.7.

Listing 4.13 RotationAndColors.java

Listing 4.13 RotationAndColors.java

There’s a subtle difference between the row with the variable borders O (cell 2 in row 3 of figure 4.7) and the row with the uniform borders ©. Whenever you use a method that changes a property of a single border, the setUseVariableBor-ders(true) method is invoked. This will cause the borders to be drawn within the cell boundaries and the different parts to be miter joined. You can also invoke this method youself on a cell with uniform borders. Because you didn’t use this method in ©, the final cell looks slightly bigger than the others: the thickness of the border is distributed equally inside and outside the cell dimensions.

And now it’s time to switch to composite mode.

Next post:

Previous post: