简体   繁体   English

C#iText7从表中删除某些标头

[英]C# iText7 Remove certain header from table

I want to remove certain header from created table. 我想从创建的表中删除某些标题。

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}

Once the height of table is bigger than PageSize.A4.GetHeight()(suppose we are using A4 Content), it automatically generates several pages and add above header. 一旦表格的高度大于PageSize.A4.GetHeight()(假设我们正在使用A4内容),它将自动生成多个页面并在标题上方添加。 From second page, i want to remove headerTable2. 从第二页,我想删除headerTable2。 How can i do it? 我该怎么做? Please help me. 请帮我。 Thanks. 谢谢。

I've been mulling over your questionn quite for some time and, unfortunately, haven't come to any plausible solution. 很长时间以来,我一直在考虑您的问题,但是不幸的是,您还没有找到任何可行的解决方案。

In iText7 in order to override the behavior of certain layout element one should extend its default renderer (for a table it would be the TableRenderer ) and then set the instance of this custom renderer on the element one wants to process. 在iText7中,为了覆盖某些布局元素的行为,应该扩展其默认渲染器(对于一个表,它应该是TableRenderer ),然后在要处理的元素上设置此自定义渲染器的实例。

One can get the header of the table with Table#getHeader() element and set a rendere on it, however there are two issus that are not easy to overcome: 一个可以使用Table#getHeader()元素获取表头并在其上设置一个rendere的方法,但是存在两个不易克服的问题:

1) for each page iText recreates the renderer, so you cannot suppose that one renderer instance will be propagated to overflow renderer of the table. 1)对于每个页面,iText都会重新创建渲染器,因此您不能假设一个渲染器实例将传播到表的溢出渲染器。 To know whether the renderer have been in use or not, one can introduce some static fields, of course, but 要知道渲染器是否一直在使用中,当然可以引入一些静态字段,但是

2) the header's borders are processed implicitly inside the parent table's layout method. 2)在父表的layout方法中隐式处理标题的边框。 And because there are a lot of edge cases with tables, the default layout method is indeed very complex, it'd be a nigthmare to override it. 而且由于表的边缘情况很多,因此默认的layout方法确实非常复杂,因此覆盖它会有些困难。 More than that, a lot of TableRenderer 's fields have either private or default access, so it'd caus eyou additional difficulties. 不仅如此,许多TableRenderer的字段都具有私有或默认访问权限,因此会给您带来其他困难。

That's why I think you have to face up to the fact that it's impossible to process the table headers in a way you want. 这就是为什么我认为您必须直面这样的事实,即不可能以所需的方式处理表头。

But what about just headers? 但是仅仅是标题呢? iText provides customers with the IEvent functionality. iText为客户提供IEvent功能。 One can implement a BEGIN_PAGE (or END_PAGE) event (in your case it would be the header drawing) and make the document listen to it. 可以实现一个BEGIN_PAGE(或END_PAGE)事件(在您的情况下,它是标题图),并使文档侦听它。 Once the event has been caught, the drawing will be performed. 捕获事件后,将执行绘图。

Let's look how it could be achieved. 让我们看看如何实现它。

Handling the event (TableHeaderEventHandler in the example below) is quite simple: 处理事件(以下示例中的TableHeaderEventHandler)非常简单:

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

And that's how one can implement this event: 这就是实现此事件的方式:

    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);
    }
}

In the snippet above I reinitialize the header once it's been placed on the first page. 在上面的代码段中,一旦将标题放置在首页上,我将对其进行初始化。 Please mind the processing of the document's margins: you may not want the page's content to interfere with the header, and that requires special attention: 请注意文档边距的处理:您可能不希望页面的内容干扰页眉,因此需要特别注意:

        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);

The sample which I've been playing with you can find on iText's website or github: https://github.com/itext/i7js-examples/blob/develop/src/test/java/com/itextpdf/samples/sandbox/events/TableHeader.java 我一直在与您一起玩的示例可以在iText的网站或github上找到: https : //github.com/itext/i7js-examples/blob/develop/src/test/java/com/itextpdf/samples/sandbox/事件/ TableHeader.java

There are, however, some very obvious flaws in the solution above: 但是,上述解决方案中存在一些非常明显的缺陷:

1) One should handle border-collapsing by themselves. 1)一个人应该自己处理border-collapsing

That's a tough one, and a general solution would require a lot of contemplation. 这是一个艰难的过程,一个通用的解决方案将需要大量的考虑。 However to solve a particular case, one can just calculate the space in a such way that the borders are placed correctly. 但是,要解决特定情况,只需以正确放置边界的方式计算空间即可。

2) One should update the document's area wisely. 2)应该明智地更新文档区域。

Let's look at the resultant pdf produce by the code above. 让我们看看上面的代码生成的pdf格式。 You may wonder why there is a gap between the header and the document's other elements on the second page. 您可能想知道为什么页眉和第二页上文档的其他元素之间存在间隙。 And what's more amazing, why there is no gap on the third+ page: 更令人惊讶的是,为什么第三页以上没有空隙: 在此处输入图片说明

The reason is as follows: when the event is handled, the next page has already been added to the document. 原因如下:处理事件时,下一页已添加到文档中。 How to overcome it? 如何克服呢? As I said in the beginning, usually one overrides a renderer (here it's the DocumentRenderer ) to handle it. 就像我在一开始所说的那样,通常会覆盖一个渲染器(这里是DocumentRenderer )来处理它。 For more information, please look at this answer: IText 7 How To Add Div or Paragraph in Header Without Overlapping Page Content? 有关更多信息,请参见以下答案: IText 7如何在页眉中添加Div或段落而不重叠页面内容?

Hope that would be useful! 希望这会有用!

PS Although the answer has been given in Java, there should be no problem for you to reproduce it in C#, because the API is quite the same. PS尽管答案是用Java给出的,但是用C#再现它应该没有问题,因为API完全相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM