C#iText7从表

时间:2019-02-02 03:16:34

标签: c# itext7

我想从创建的表中删除某些标题。

Table table = new Table(2).SetWidth(iText.Layout.Properties.UnitValue.CreatePercentValue(100));
Table headerTable1 = new Table(2).SetWidth(iText.Layout.Properties.UnitValue.CreatePercentValue(100));
headerTable1.AddCell(new Cell().Add(new Paragraph("Test1")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));
headerTable1.AddCell(new Cell().Add(new Paragraph("Test2")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));

table.AddHeaderCell(new Cell(1,2).Add(headerTable1));

Table headerTable2 = new Table(2).SetWidth(iText.Layout.Properties.UnitValue.CreatePercentValue(100));
headerTable2.AddCell(new Cell().Add(new Paragraph("Test1")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));
headerTable2.AddCell(new Cell().Add(new Paragraph("Test2")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));

table.AddHeaderCell(new Cell(1,2).Add(headerTable2));

Table headerTable3 = new Table(2).SetWidth(iText.Layout.Properties.UnitValue.CreatePercentValue(100));
headerTable3.AddCell(new Cell().Add(new Paragraph("Test1")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));
headerTable3.AddCell(new Cell().Add(new Paragraph("Test2")).SetWidth(iText.Layout.properties.UnitValue.CreatePercentValue(50)));

table.AddHeaderCell(new Cell(1,2).Add(headerTable3));

{Add Multiple Cells to Table}

一旦表格的高度大于PageSize.A4.GetHeight()(假设我们使用的是A4内容),它将自动生成多个页面并在标题上方添加。 从第二页,我想删除headerTable2。我该怎么做?请帮我。谢谢。

1 个答案:

答案 0 :(得分:1)

很长一段时间以来,我一直在考虑您的问题,但不幸的是,没有找到任何可行的解决方案。

在iText7中,为了覆盖某些布局元素的行为,应扩展其默认渲染器(对于表,它应为TableRenderer),然后在一个想要设置的元素上设置此自定义渲染器的实例。过程。

一个人可以使用Table#getHeader()元素获取表头并在其上设置一个rendere,但是存在两个不易克服的问题:

1)对于每个页面,iText都会重新创建渲染器,因此您不能假设一个渲染器实例将传播到表的溢出渲染器。要知道渲染器是否一直在使用中,当然可以引入一些静态字段,但是

2)标头的边框在父表的layout方法中隐式处理。而且由于表的边缘情况很多,因此默认的layout方法确实非常复杂,因此重写它是一个麻烦。不仅如此,TableRenderer的许多字段都具有私有或默认访问权限,因此会给您带来其他麻烦。

这就是为什么我认为您必须面对这样一个事实,即不可能以您想要的方式处理表头。

但是仅标题呢? iText为客户提供IEvent功能。可以实现一个BEGIN_PAGE(或END_PAGE)事件(在您的情况下,它是标题图),并使文档侦听它。捕获事件后,将执行绘图。

让我们看看如何实现它。

处理事件(在下面的示例中为TableHeaderEventHandler)非常简单:

    TableHeaderEventHandler handler = new TableHeaderEventHandler(doc);
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler);

这就是实现此事件的方式:

    public class TableHeaderEventHandler implements IEventHandler {
    protected Table table;
    protected float tableHeight;
    protected Document doc;

    public TableHeaderEventHandler(Document doc) {
        this.doc = doc;
        initTable(false);
    }

    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);
        Rectangle rect = new Rectangle(pdfDoc.getDefaultPageSize().getX() + doc.getLeftMargin(),
                pdfDoc.getDefaultPageSize().getTop() - doc.getTopMargin(), 523, getTableHeight());
        new Canvas(canvas, pdfDoc, rect)
                .add(table);

        if (1 == doc.getPdfDocument().getPageNumber(page)) {
            initTable(true);
        }
    }

    public float getTableHeight() {
        return tableHeight;
    }

    private void initTable(boolean removeTheSecondRow) {
        table = new Table(3);
        table.addCell("row 1, 1");
        table.addCell(new Cell(1, 2).add(new Paragraph("row 1, 2 3")));
        if (!removeTheSecondRow) {
            table.addCell(new Cell(1, 3).add(new Paragraph("row 2, 1 2 3")));
        }
        table.addCell("row 3, 1");
        table.addCell("row 3, 2");
        table.addCell("row 3, 3");
        TableRenderer renderer = (TableRenderer) table.createRendererSubTree();
        renderer.setParent(new Document(new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))).getRenderer());
        tableHeight = renderer.layout(new LayoutContext(new LayoutArea(0, PageSize.A4))).getOccupiedArea().getBBox().getHeight();
        doc.setMargins(120 + tableHeight, 36, 36, 36);
    }
}

在上面的代码段中,一旦将标题放置在第一页上,我将对其进行初始化。 请注意对文档页边距的处理:您可能不希望页面的内容干扰页眉,因此需要特别注意:

        TableRenderer renderer = (TableRenderer) table.createRendererSubTree();
        renderer.setParent(new Document(new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))).getRenderer());
        tableHeight = renderer.layout(new LayoutContext(new LayoutArea(0, PageSize.A4))).getOccupiedArea().getBBox().getHeight();
        doc.setMargins(120 + tableHeight, 36, 36, 36);

我一直在与您一起玩的示例可以在iText的网站或github上找到:https://github.com/itext/i7js-examples/blob/develop/src/test/java/com/itextpdf/samples/sandbox/events/TableHeader.java

但是,上述解决方案中存在一些非常明显的缺陷:

1)一个人应该自己处理border-collapsing

这是一个艰难的过程,一个通用的解决方案将需要大量的考虑。但是,要解决特定情况,只需以正确放置边框的方式计算空间即可。

2)应该明智地更新文档区域。

让我们看看上面的代码生成的pdf。您可能想知道为什么页眉和第二页上文档的其他元素之间存在间隙。更令人惊讶的是,为什么第三页以上没有空隙: enter image description here

原因如下:处理事件时,下一页已添加到文档中。 如何克服呢?就像我在一开始所说的那样,通常会覆盖一个渲染器(这里是DocumentRenderer)来处理它。有关更多信息,请查看以下答案:IText 7 How To Add Div or Paragraph in Header Without Overlapping Page Content?

希望会有用!

P.S。尽管答案是用Java给出的,但是用C#再现它应该没有问题,因为API完全相同。