如何将圆角边框应用于 table(单页/多页)?
How to apply round corner border to table (single page / multipage)?
我想将圆角边框应用于 table。这个 table 是动态的。这意味着它可以增长到多个页面,也可以容纳在一个页面中。
如果table出现在单页中,则所有四个角单元格的最外角应绘制为圆角。
如果 table 增长到多页(比如 3 页),则所有 3 页的所有四个角单元格的最外角都应绘制为圆形。
这是我用来实现上述场景的方法。
public void createPdf(String dest) throws FileNotFoundException {
PdfWriter writer = new PdfWriter(DEST);
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc, PageSize.A4, false);
Table table = new Table(3);
for (int i=0; i < 100; i++) {
for (int j=0; j < 3; j++) {
table.addCell(new Cell().add(new Paragraph("Cell content")));
}
}
table.setNextRenderer(new TableBorderRenderer(table));
document.add(table);
document.close();
}
TableBorderRenderer.java
public class TableBorderRenderer extends TableRenderer {
public TableBorderRenderer(Table modelElement) {
super(modelElement);
}
@Override
public IRenderer getNextRenderer() {
return new TableBorderRenderer((Table) modelElement);
}
@Override
protected void drawBorders(DrawContext drawContext) {
Rectangle rect = getOccupiedAreaBBox();
PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());
// drawing white rectangle over table border in order to hide it.
aboveCanvas.saveState().setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
// drawing red round rectangle which will be shown as boundary.
aboveCanvas.saveState().setLineWidth(0.5f).setStrokeColor(new DeviceRgb(255,0,0)).roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
super.drawBorders(drawContext);
}
}
现在代码可以正常工作,但渲染有问题。当我在 table 边框上方绘制白色边框时,它并没有完全重叠。此外,外部红色边框略微超出预期区域。简单来说,白色矩形和红色矩形不重合。因此,外边界和单元格边界之间存在一些间隙。
我附上了上面代码生成的输出。要注意到此问题,您可能需要稍微缩放 PDF。
我对此有一些疑问:
我正在使用 top canvas 来获得预期的解决方案。但是有什么方法可以在渲染时直接修改 table 边框吗?我试过了
drawContext.getCanvas()
.saveState()
.roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
但在这种方法中,边界与单元格边界重叠(也需要单元格边界)。如果我遗漏了一些东西来防止这个问题,请指导我。
谢谢。
getOccupiedAreaBBox
方法给出了边框区域的外边界框。但是,边框有自己的厚度,当您默认在 PDF 中绘制线条时,您应该将线条的中心传递给绘图操作,同时传递外部 bbox 坐标,因此边距小且重叠不精确。
要解决此问题,您需要将边框线宽度的一半添加到矩形的所有边缘:
float lineWidth = 0.5f;
rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);
综上所述,定制代码如下:
@Override
protected void drawBorders(DrawContext drawContext) {
Rectangle rect = getOccupiedAreaBBox();
PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());
float lineWidth = 0.5f;
rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);
// drawing white rectangle over table border in order to hide it.
aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
// drawing red round rectangle which will be shown as boundary.
aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,0,0))
.roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
super.drawBorders(drawContext);
}
产生以下视觉结果:
我想将圆角边框应用于 table。这个 table 是动态的。这意味着它可以增长到多个页面,也可以容纳在一个页面中。
如果table出现在单页中,则所有四个角单元格的最外角应绘制为圆角。 如果 table 增长到多页(比如 3 页),则所有 3 页的所有四个角单元格的最外角都应绘制为圆形。
这是我用来实现上述场景的方法。
public void createPdf(String dest) throws FileNotFoundException {
PdfWriter writer = new PdfWriter(DEST);
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc, PageSize.A4, false);
Table table = new Table(3);
for (int i=0; i < 100; i++) {
for (int j=0; j < 3; j++) {
table.addCell(new Cell().add(new Paragraph("Cell content")));
}
}
table.setNextRenderer(new TableBorderRenderer(table));
document.add(table);
document.close();
}
TableBorderRenderer.java
public class TableBorderRenderer extends TableRenderer {
public TableBorderRenderer(Table modelElement) {
super(modelElement);
}
@Override
public IRenderer getNextRenderer() {
return new TableBorderRenderer((Table) modelElement);
}
@Override
protected void drawBorders(DrawContext drawContext) {
Rectangle rect = getOccupiedAreaBBox();
PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());
// drawing white rectangle over table border in order to hide it.
aboveCanvas.saveState().setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
// drawing red round rectangle which will be shown as boundary.
aboveCanvas.saveState().setLineWidth(0.5f).setStrokeColor(new DeviceRgb(255,0,0)).roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
super.drawBorders(drawContext);
}
}
现在代码可以正常工作,但渲染有问题。当我在 table 边框上方绘制白色边框时,它并没有完全重叠。此外,外部红色边框略微超出预期区域。简单来说,白色矩形和红色矩形不重合。因此,外边界和单元格边界之间存在一些间隙。 我附上了上面代码生成的输出。要注意到此问题,您可能需要稍微缩放 PDF。
我对此有一些疑问: 我正在使用 top canvas 来获得预期的解决方案。但是有什么方法可以在渲染时直接修改 table 边框吗?我试过了
drawContext.getCanvas()
.saveState()
.roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
但在这种方法中,边界与单元格边界重叠(也需要单元格边界)。如果我遗漏了一些东西来防止这个问题,请指导我。
谢谢。
getOccupiedAreaBBox
方法给出了边框区域的外边界框。但是,边框有自己的厚度,当您默认在 PDF 中绘制线条时,您应该将线条的中心传递给绘图操作,同时传递外部 bbox 坐标,因此边距小且重叠不精确。
要解决此问题,您需要将边框线宽度的一半添加到矩形的所有边缘:
float lineWidth = 0.5f;
rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);
综上所述,定制代码如下:
@Override
protected void drawBorders(DrawContext drawContext) {
Rectangle rect = getOccupiedAreaBBox();
PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());
float lineWidth = 0.5f;
rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);
// drawing white rectangle over table border in order to hide it.
aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
// drawing red round rectangle which will be shown as boundary.
aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,0,0))
.roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
super.drawBorders(drawContext);
}
产生以下视觉结果: