Itext7 CellRenderer 并不总是有效

Itext7 CellRenderer does not always work

我正在使用 Itext7 创建一个包含 table 的 pdf。
table 占多页。
我还重写了单元格渲染器以将表单域添加到某些单元格。
我注意到当 table 转到新页面时,第一行不会触发 CellRender class.
的绘制方法 我在下面放了一些代码以便更好地理解。

...
//adding the cells to table
for (int i = 0; i < 10; i++) {
    addRow(table,i);
}
...
//addRow implementation
private void addRow(Table table, int row) throws IOException {
    table.startNewRow();

    PdfFont zapfdingbats = PdfFontFactory.createFont(FontConstants.ZAPFDINGBATS);

    Cell checkBoxCell = new Cell().add(new Paragraph("o").setFont(zapfdingbats).setMargins(9, 0, 0, 11)).setKeepTogether(true);
    checkBoxCell.setNextRenderer(new CheckboxCellRenderer(checkBoxCell, "cb"+row));
    table.addCell(checkBoxCell);
    ...
    //other cells here
}
...
//The implementation of the custom CellRender
protected class CheckboxCellRenderer extends CellRenderer {
    protected String name;

    public CheckboxCellRenderer(Cell modelElement, String name) {
        super(modelElement);
        this.name = name;
    }
    //this method is not triggered for the first row when a new page is created
    @Override
    public void draw(DrawContext drawContext) {
        System.out.println(name);
        super.draw(drawContext);
        float x = getOccupiedAreaBBox().getLeft();
        float y = getOccupiedAreaBBox().getBottom();
        float width = getOccupiedAreaBBox().getRight()-getOccupiedAreaBBox().getLeft();
        float height = getOccupiedAreaBBox().getTop()-getOccupiedAreaBBox().getBottom();
        Rectangle rect = new Rectangle(x+5, y+5, width-10, height-10);
        PdfTextFormField pdfTextFormField = PdfFormField.createText(drawContext.getDocument(), rect, name);
        PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(pdfTextFormField);
    }
}

我做错了什么?

如果您转到新页面,则会丢弃您的 Renderer 并创建一个新的 Renderer 对象。这样做是为了避免在模型对象发生某些变化时混淆状态。在这种情况下,方法getNextRenderer被调用:

/**
 * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
 * {@link #layout(LayoutContext)} is called more than once.
 * @return new renderer instance
 */
IRenderer getNextRenderer();

因此,如果您只是在自定义中重写此方法,应该没问题 CheckboxCellRenderer class:

@Override
public IRenderer getNextRenderer() {
    return new CheckboxCellRenderer(getModelElement(), name);
}

您没有覆盖一个非常重要的方法:public IRenderer getNextRenderer()

如果单元格无法放置在页面上,iText 会创建一个溢出单元格(请参阅 protected AbstractRenderer createOverflowRenderer(int layoutResult) 方法。如果您不覆盖 getNextRenderer 默认情况下,iText 将使用其 getModelElement( ).

所以我建议你应该添加 summat: @Override public IRenderer getNextRenderer() { return new CheckboxCellRenderer(getModelElement(), name); }

我已经使用您的代码创建了下一个示例,它按您预期的那样工作。 `

public class ArrayToTable extends GenericTest {
public static final String DEST = "./target/test/resources/sandbox/tables/array_to_table.pdf";

public static void main(String[] args) throws Exception {
    File file = new File(DEST);
    file.getParentFile().mkdirs();
    new CustomRendererTest().manipulatePdf(DEST);
}

@Override
protected void manipulatePdf(String dest) throws Exception {
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
    Document doc = new Document(pdfDoc);

    Table table = new Table(1);
    //adding the cells to table
    for (int i = 0; i < 25; i++) {
        addRow(table, i);
    }

    doc.add(table);
    doc.close();
}

    //addRow implementation
    private void addRow(Table table, int row) throws IOException {
        table.startNewRow();

        PdfFont zapfdingbats = PdfFontFactory.createFont(FontConstants.ZAPFDINGBATS);

        Cell checkBoxCell = new Cell().add(new Paragraph("o").setFont(zapfdingbats).setMargins(9, 0, 0, 11)).setKeepTogether(true);
        checkBoxCell.setNextRenderer(new CheckboxCellRenderer(checkBoxCell, "cb"+row));
        table.addCell(checkBoxCell);
        //other cells here
    }

    //The implementation of the custom CellRender
    protected class CheckboxCellRenderer extends CellRenderer {
        protected String name;

        public CheckboxCellRenderer(Cell modelElement, String name) {
            super(modelElement);
            this.name = name;
        }
        //this method is not triggered for the first row when a new page is created
        @Override
        public void draw(DrawContext drawContext) {
            System.out.println(name);
            super.draw(drawContext);
            float x = getOccupiedAreaBBox().getLeft();
            float y = getOccupiedAreaBBox().getBottom();
            float width = getOccupiedAreaBBox().getRight()-getOccupiedAreaBBox().getLeft();
            float height = getOccupiedAreaBBox().getTop()-getOccupiedAreaBBox().getBottom();
            Rectangle rect = new Rectangle(x+5, y+5, width-10, height-10);
            PdfTextFormField pdfTextFormField = PdfFormField.createText(drawContext.getDocument(), rect, name);
            PdfAcroForm.getAcroForm(drawContext.getDocument(), true).addField(pdfTextFormField);
        }

        @Override
        public IRenderer getNextRenderer() {
            return new CheckboxCellRenderer(getModelElement(), name);
        }

    }

} `