「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」
PDF神器iText英文版翻译与学习
作者: 薛大郎.
英文原版: iText in Action 2nd Edition.pdf
坚持. 分享. 成长. 利他 !
一. 前言
不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高
每个人生来都是一个有天分的天使, 只是你可能被其他诱惑或者帅气压制了。 ---- 这是我说的
我们都在用力的活着, 酸甜苦辣里 醒过也醉过, 也曾倔强脆弱 依然执着,相信花开以后 会结果.
每一个成年人都不容易, 但是就是因为这些不容易才让我们的努力看起来那么精彩. 突然看到console中梵高的这句话, 突然感觉, 我们还是拼一拼, 对于我来说可能就是虽然可能年龄稍高了. 但是我还可以在喜欢的 code 的世界, 卷出自己的精彩. 也许天赋异禀!
二.正文.
7. 学习iText中的事件.
每个项目中都有各种各样的事件, 大部分的都是后来才想到的, 才强加上了事件. 为什么说是强加的呢, 因为并没有很好的抽象设计, 大部分都应该在项目之初做好相关设计.
之前的篇章中我们学了很多iText的内容, 包括chunk, paragraph,chapter,section, pdfpTable,pdfpcell等等. 我们发现其实很多时候并没有关心打开一个新页面, 当然也不是不可以, 我们只需要调用doc.newPage()
即可. 但是我们更多的是想着能够在每页都添加页头页脚, 以及添加水印以及页数等. 那该怎么办呢. iText已经为我们准备好了方便使用的 Event相关设计, 之前也提到过 PdfPageEvent
.
但是我们先从包装table的table和cell的事件说起.
PdfPTable 和 PdfPCell 为我们提供了两个方法: PdfPTable.setTableEvent() 和 PdfPCell.setCellEvent() ;我们先来看下源码, 这两个方法基本一致:
PdfPTable.setTableEvent();
public void setTableEvent(final PdfPTableEvent event) {
// 如果参数为null, 即删除表格的事件. 这个要注意.
if (event == null)
this.tableEvent = null;
// 如果当前无tableEvent, 则设置为调用参数的
else if (this.tableEvent == null)
this.tableEvent = event;
// 如果当前的table事件为PdfPTableEventForwarder的实例, 则强转并添加当前事件.
else if (this.tableEvent instanceof PdfPTableEventForwarder)
((PdfPTableEventForwarder) this.tableEvent).addTableEvent(event);
// 最后如果上边的都不是, 也就是说table已经有了事件但是又不是PdfPTableEventForwarder的实例, 则改为添加了之前事件和当前要设置的事件的总的 PdfPTableEventForwarder;
else {
PdfPTableEventForwarder forward = new PdfPTableEventForwarder();
forward.addTableEvent(this.tableEvent);
forward.addTableEvent(event);
this.tableEvent = forward;
}
}
// 与Table中的setEvent 逻辑基本一致, 不做注释, 大家在设置的时候注意即可.
PdfPCell.setCellEvent();
public void setCellEvent(PdfPCellEvent cellEvent) {
if (cellEvent == null)
this.cellEvent = null;
else if (this.cellEvent == null)
this.cellEvent = cellEvent;
else if (this.cellEvent instanceof PdfPCellEventForwarder)
((PdfPCellEventForwarder)this.cellEvent).addCellEvent(cellEvent);
else {
PdfPCellEventForwarder forward = new PdfPCellEventForwarder();
forward.addCellEvent(this.cellEvent);
forward.addCellEvent(cellEvent);
this.cellEvent = forward;
}
}
iText实战中有一个例子, 设置基数行为黄色, 但是偶数行不设置背景颜色, 当然我们可以交替设置默认cell的背景颜色, 但是书中有一个特例就是这个表格超过了一页, 而每页只有27行, 那么在第二页的时候, 那么除了第一行的标题行外, 第二行就改为了黄色, 也就是说第二页就是偶数行成了黄色背景. 这不是我们所期望的. 而要实现这个, 我们只需要使用iText为我们提供的event设计.
// 实现PdfPTableEvent, 交替背景类即是一个tableEvent了.
Public class AlternatingBackground implements PdfPTableEvent {
/* 在渲染结束时调用此方法。 文本或图形被添加到canvases中包含的 4 个PdfContentByte之一。
* 这四个 canvases的索引(即对应key)是:
* PdfPTable.BASECANVAS - 原始PdfContentByte 。 放在这里的任何东西都会在table底下。
* PdfPTable.BACKGROUNDCANVAS - 背景所在的层。
* PdfPTable.LINECANVAS - 线条所在的层。
* PdfPTable.TEXTCANVAS - 文本所在的层。 放在这里的任何东西都会摆在桌子上。
* 这些层按顺序放置在彼此的顶部。
* widths和heights具有单元格的坐标。 widths[]的大小是行数。 widths中的每个子数组对应于 x 列边框位置,其中第一个元素是左侧表格边框的 x 坐标,最后一个元素是右侧表格边框的 x 坐标。 如果不使用 colspan,则所有子数组的widths都相同。 对于heights ,第一个元素是顶部表格边框的 y 坐标,最后一个元素是底部表格边框的 y 坐标。
*
* 参数:
* table – 当前的PdfPTable
* widths – 具有单元格 x 位置的数组数组。 它具有行数的长度
* heights – 包含单元格 y 位置的数组。 它的长度为行数 + 1
* headerRows – 为标题定义的行数。
* rowStart – 标题后的第一行号
* canvases – PdfContentByte数组
*/
public void tableLayout(PdfPTable table, float[][] widths, float[] heights,
int headerRows, int rowStart, PdfContentByte[] canvases) {
// 用以记录列数
int columns;
// 每一个黄色矩形
Rectangle rect;
// 计算footer数 = 总列数 - footer数.
int footer = widths.length - table.getFooterRows();
// 计算header数
int header = table.getHeaderRows() - table.getFooterRows() + 1;
// 每两行设置一次, 是从每一页里的这个表格来计算的.
for (int row = header; row < footer; row += 2) {
// 列数
columns = widths[row].length - 1;
// 开始画这个矩形.
rect = new Rectangle(widths[row][0], heights[row], widths[row][columns], heights[row + 1]);
rect.setBackgroundColor(BaseColor.YELLOW);
rect.setBorder(Rectangle.NO_BORDER);
// 使用的是最下边的那一层.
canvases[PdfPTable.BASECANVAS].rectangle(rect);
}
}
}