2

In itext 5, it can be used cell events to compute a subtotal of a table column. How can this be done in itext 7?

The itext 5 example can be found in this URL: http://developers.itextpdf.com/examples/tables/using-cell-events-add-special-content#2887-subtotal.java

1 Answers1

6

There is currently no direct alternative of cell event functionality in iText7. Howerver, the desired output can be achieved using rich rendering mechanism which allows a lot more than just events.

I will provide just one of the possible ways to implement a subtotal of table on the page. Total is easy and thus I'm leaving it out of the scope of the answer.

For the starters, we will need a class responsible for calculations:

private static class SubtotalHandler {
    private int subtotalSum;

    public void reset() {
        subtotalSum = 0;
    }

    public void add(int val) {
        subtotalSum += val;
    }

    public int get() {
        return subtotalSum;
    }
}

The code for generating the table itself will look like this:

Table table = new Table(UnitValue.createPercentArray(new float[] {1, 1})).setWidth(400);
table.setHorizontalAlignment(HorizontalAlignment.CENTER);

// Create our calculating class instance
SubtotalHandler handler = new SubtotalHandler();
for (int i = 0; i < 200; i++) {
    table.addCell(new Cell().add(String.valueOf(i + 1)));
    int price = 10;
    Cell priceCell = new Cell().add(String.valueOf(price));
    // Note that we set a custom renderer that will interact with our handler
    priceCell.setNextRenderer(new SubtotalHandlerAwareCellRenderer(priceCell, handler, price));
    table.addCell(priceCell);
}
table.addFooterCell(new Cell().add("Subtotal"));
Cell subtotalCell = new Cell();
// We create a custom renderer for the subtotal value itself as well because the text of the cell will depend on the state of the subtotal handler
subtotalCell.setNextRenderer(new SubtotalCellRenderer(subtotalCell, handler));
table.addFooterCell(subtotalCell);

Renderers of cells with price just tell the subtotal handler that some amount has been added:

private static class SubtotalHandlerAwareCellRenderer extends CellRenderer {
    private SubtotalHandler subtotalHandler;
    private int price;

    public SubtotalHandlerAwareCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler, int price) {
        super(modelElement);
        this.subtotalHandler = subtotalHandler;
        this.price = price;
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        subtotalHandler.add(price);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new SubtotalHandlerAwareCellRenderer((Cell) modelElement, subtotalHandler, price);
    }
}

When it comes to the rendering of the footer cell, the corresponding cell asks the subtotal handler about the amount and prints it, and resets the subtotal handler afterwards:

private static class SubtotalCellRenderer extends CellRenderer {
    private SubtotalHandler subtotalHandler;

    public SubtotalCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler) {
        super(modelElement);
        this.subtotalHandler = subtotalHandler;
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        new Canvas(drawContext.getCanvas(), drawContext.getDocument(), occupiedArea.getBBox()).
                showTextAligned(String.valueOf(subtotalHandler.get()), occupiedArea.getBBox().getX() + 3,
                        occupiedArea.getBBox().getY() + 3, TextAlignment.LEFT);
        subtotalHandler.reset();
    }

    @Override
    public IRenderer getNextRenderer() {
        return new SubtotalCellRenderer((Cell) modelElement, subtotalHandler);
    }
}

The output looks like this:

part of the output

Alexey Subach
  • 11,903
  • 7
  • 34
  • 60