C# iText7 从 table 中删除某些 header
C# iText7 Remove certain header from table
我想从创建的 table 中删除某些 header。
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}
一旦table的高度大于PageSize.A4.GetHeight()(假设我们使用A4内容),它会自动生成几页并添加到header之上。
从第二页开始,我想删除 headerTable2。我该怎么做?请帮我。谢谢
我已经考虑了你的问题一段时间了,不幸的是,还没有得出任何合理的解决方案。
在 iText7 中,为了覆盖某些布局元素的行为,应该扩展其默认渲染器(对于 table 它将是 TableRenderer
),然后设置此自定义渲染器的实例在要处理的元素上。
可以用Table#getHeader()
元素获取table的header,并在其上设置渲染,但是有两个问题不容易克服:
1) iText 为每一页重新创建渲染器,因此您不能假设一个渲染器实例将传播到 table 的溢出渲染器。要知道渲染器是否被使用,当然可以引入一些静态字段,但是
2) header 的边框在 parent table 的 layout
方法中隐式处理。而且因为 tables 有很多边缘情况,默认的 layout
方法确实非常复杂,覆盖它是一个噩梦。不仅如此,TableRenderer
的许多字段都具有私有或默认访问权限,因此会给您带来额外的困难。
这就是为什么我认为你必须正视这样一个事实,即不可能以你想要的方式处理 table header。
但是 header 呢? iText 为客户提供 IEvent
功能。可以实施 BEGIN_PAGE(或 END_PAGE)事件(在您的情况下是 header 绘图)并让文档收听它。一旦捕获到事件,就会执行绘图。
让我们看看它是如何实现的。
处理事件(下例中的 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);
}
}
在上面的代码片段中,我将 header 放在第一页后重新初始化。
请注意文档页边距的处理:您可能不希望页面内容干扰 header,这一点需要特别注意:
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
。
这是一个棘手的问题,一个通用的解决方案需要大量的思考。然而,为了解决特定情况,可以只计算 space 以正确放置边框的方式。
2) 明智地更新文档的区域。
让我们看看上面代码生成的pdf结果。您可能想知道为什么 header 和第二页上文档的其他元素之间存在间隙。还有更神奇的是,为什么第三+页没有空隙:
原因如下:事件处理时,下一页已经添加到文档中。
如何克服呢?正如我在一开始所说的,通常会覆盖渲染器(这里是 DocumentRenderer
)来处理它。有关更多信息,请查看此答案:IText 7 How To Add Div or Paragraph in Header Without Overlapping Page Content?
希望有用!
P.S。虽然在Java中已经给出了答案,但是你用C#重现应该没有问题,因为API是完全一样的。
我想从创建的 table 中删除某些 header。
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}
一旦table的高度大于PageSize.A4.GetHeight()(假设我们使用A4内容),它会自动生成几页并添加到header之上。 从第二页开始,我想删除 headerTable2。我该怎么做?请帮我。谢谢
我已经考虑了你的问题一段时间了,不幸的是,还没有得出任何合理的解决方案。
在 iText7 中,为了覆盖某些布局元素的行为,应该扩展其默认渲染器(对于 table 它将是 TableRenderer
),然后设置此自定义渲染器的实例在要处理的元素上。
可以用Table#getHeader()
元素获取table的header,并在其上设置渲染,但是有两个问题不容易克服:
1) iText 为每一页重新创建渲染器,因此您不能假设一个渲染器实例将传播到 table 的溢出渲染器。要知道渲染器是否被使用,当然可以引入一些静态字段,但是
2) header 的边框在 parent table 的 layout
方法中隐式处理。而且因为 tables 有很多边缘情况,默认的 layout
方法确实非常复杂,覆盖它是一个噩梦。不仅如此,TableRenderer
的许多字段都具有私有或默认访问权限,因此会给您带来额外的困难。
这就是为什么我认为你必须正视这样一个事实,即不可能以你想要的方式处理 table header。
但是 header 呢? iText 为客户提供 IEvent
功能。可以实施 BEGIN_PAGE(或 END_PAGE)事件(在您的情况下是 header 绘图)并让文档收听它。一旦捕获到事件,就会执行绘图。
让我们看看它是如何实现的。
处理事件(下例中的 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);
}
}
在上面的代码片段中,我将 header 放在第一页后重新初始化。 请注意文档页边距的处理:您可能不希望页面内容干扰 header,这一点需要特别注意:
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
。
这是一个棘手的问题,一个通用的解决方案需要大量的思考。然而,为了解决特定情况,可以只计算 space 以正确放置边框的方式。
2) 明智地更新文档的区域。
让我们看看上面代码生成的pdf结果。您可能想知道为什么 header 和第二页上文档的其他元素之间存在间隙。还有更神奇的是,为什么第三+页没有空隙:
原因如下:事件处理时,下一页已经添加到文档中。
如何克服呢?正如我在一开始所说的,通常会覆盖渲染器(这里是 DocumentRenderer
)来处理它。有关更多信息,请查看此答案:IText 7 How To Add Div or Paragraph in Header Without Overlapping Page Content?
希望有用!
P.S。虽然在Java中已经给出了答案,但是你用C#重现应该没有问题,因为API是完全一样的。