Is it possible to attach multiple layout events to a PdfPCell?

Tags: tablesiText 7

I'm not sure if it's possible to set multiple events. I would like to separate different cell options in separate events based on my business logic. Sometimes I want to draw an ellipse in it, sometimes a square (or anything else). It would be nice if I could simply attach the events that I need.

Posted on StackOverflow on Mar 18, 2015 by Robert

Take into account that in iText 7 we use Table and Cell classes instead of PdfPTable and PdfPCell.

There are no CellEvents anymore, and we now work with CellRenderers. You can override the draw() method and set the behavior of the cell depending on your business logic. Just send a parameter condition (can be any type you want) to the MyCellRenderer constructor like this:

protected void createPdf(String dest) throws Exception {
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
    Document doc = new Document(pdfDoc);
    Table table = new Table(2);
    Cell cell;
    int condition;
    for (int i = 1; i < 5; i++) {
        condition = i; //or any other value
        cell = new Cell().add("I'm a cell");
        cell.setNextRenderer(new MyCellRenderer(cell, condition));
        table.addCell(cell);
    }
    doc.add(table);
    doc.close();
}

Suppose that we want to create a table with four cells and draw different geometric objects inside. The result will look like this:

Different shapes in cells
Different shapes in cells

And here is the implementation of the CellRenderer:

protected class MyCellRenderer extends CellRenderer {
    protected int condition;
 
    public MyCellRenderer(Cell modelElement, int condition) {
        super(modelElement);
        this.condition = condition;
    }
 
    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        Rectangle rect = getOccupiedAreaBBox();
        PdfCanvas canvas = drawContext.getCanvas().saveState();
        canvas.setLineCapStyle(PdfCanvasConstants.LineCapStyle.ROUND).setLineWidth(1.5f);
        switch (condition) {
            case (1): {
                canvas
                        .setStrokeColor(Color.BLUE)
                        .roundRectangle(rect.getLeft() + 80f, rect.getBottom() + 2f, rect.getWidth() - 160f, rect.getHeight() - 4f, 10f);
                break;
            }
            case (2): {
                canvas
                        .setStrokeColor(Color.YELLOW)
                        .moveTo(rect.getLeft() + 40f, rect.getBottom() + 2f)
                        .lineTo(rect.getLeft() + rect.getWidth() / 2, rect.getTop() - 2f)
                        .moveTo(rect.getLeft() + rect.getWidth() / 2, rect.getTop() - 2f)
                        .lineTo(rect.getRight() - 40f, rect.getBottom() + 2f)
                        .moveTo(rect.getRight() - 40f, rect.getBottom() + 2f)
                        .lineTo(rect.getLeft() + 40f, rect.getBottom() + 2f);
                break;
            }
            case (3): {
                canvas
                        .setStrokeColor(Color.ORANGE)
                        .rectangle(rect.getLeft() + 80f, rect.getBottom() + 5f, rect.getWidth() - 160f, rect.getHeight() - 10f);
                break;
            }
            case (4): {
                canvas
                        .setStrokeColor(Color.GREEN)
                        .ellipse(rect.getLeft() + 80f, rect.getBottom() + 5f, rect.getRight() - 80f, rect.getTop() - 5f);
                break;
            }
        }
        canvas.stroke();
        canvas.restoreState();
    }
}

Feel free to change the code according to your needs.

Click this link if you want to see how to answer this question in iText 5.