对于我的下一个问题,我需要解释一下。 :-D
在我目前的项目中,我试图用C#创建invoice-pdf。
正如你在上一个问题中所看到的那样,想要添加小计。布鲁诺帮我成功了。在我的positionTable中的每个页脚上,由于
而添加了小计,除了最后一个小计positionTable.SkipLastFooter = true;
在我的positionTable中可以有多头位置,所以我将表格设置为
positionTable.SplitLate = false;
现在我试图在最后一页上添加总框。为此我创建了一个额外的表(totalTable)。桌子应始终保持在一起。所以我设置了
totalTable.KeepTogether = true;
第一个问题是,如果totalTable不适合页面,它将在下一页上。但是位置表已经关闭,前一页上没有显示小计。
所以我决定将我的totalTable嵌套到我的positionTable中。我知道,我看到totalTable.KeepTogether = true
不再有任何影响。
是否有将单个单元格设置为SplitLate = false;
的解决方案?
+------------------------------------------+
| Pos | Menge | Text | Einzelpreis | Summe |
+------------------------------------------+
| 1 | 2 | Text | 10.00 | 20.00 |
+------------------------------------------+
| 2 | 1 | Text | 10.00 | 10.00 |
+------------------------------------------+
| 3 | 4 | Text | 10.00 | 40.00 |
+------------------------------------------+
| 4 | 2 | Text | 10.00 | 20.00 |
+==========================================+
|Sum without Tax | 90.00 |
|15% Tax | 13.50 |
|Total |103.50 |
+==========================================+
答案 0 :(得分:3)
新答案:
如评论中所示,您可以使用writeSelectedRows()
添加绝对位置的所有行:
package sandbox.tables;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPCellEvent;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import sandbox.WrapToTest;
@WrapToTest
public class SubTotal3 {
public static final String DEST = "results/tables/subtotal3.pdf";
public static void main(String[] args) throws IOException,
DocumentException {
File file = new File(DEST);
file.getParentFile().mkdirs();
new SubTotal3().createPdf(DEST);
}
class Totals {
double subtotal = 0;
double total = 0;
boolean done;
}
class SubTotalEvent implements PdfPCellEvent {
Double price;
Totals totals;
public SubTotalEvent(Totals totals, double price) {
this.totals = totals;
this.price = price;
}
public SubTotalEvent(Totals totals) {
this.totals = totals;
price = null;
}
@Override
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
if (totals.done) {
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
new Phrase(String.valueOf(totals.total)),
position.getLeft() + 2, position.getBottom() + 2, 0);
totals.total = totals.total * 1.15;
return;
}
if (price == null) {
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
new Phrase(String.valueOf(totals.subtotal)),
position.getLeft() + 2, position.getBottom() + 2, 0);
totals.subtotal = 0;
return;
}
totals.subtotal += price;
totals.total += price;
}
}
public void createPdf(String dest) throws IOException, DocumentException {
int rows = 92;
Totals totals = new Totals();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
float width = document.right() - document.left();
// header
PdfPTable header = new PdfPTable(5);
header.setWidths(new int[]{1, 1, 1, 3, 3});
header.setTotalWidth(width);
header.addCell("Pos");
header.addCell("Menge");
header.addCell("Text");
header.addCell("Einzerpreis");
header.addCell("Summe");
// definitions
PdfPTable footer = new PdfPTable(5);
footer.setWidths(new int[]{1, 1, 1, 3, 3});
footer.setTotalWidth(width);
PdfPCell cell = new PdfPCell(new Phrase("Subtotal"));
cell.setColspan(4);
footer.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new SubTotal3.SubTotalEvent(totals));
footer.addCell(cell);
// actual table
PdfPTable table = new PdfPTable(5);
table.setWidths(new int[]{1, 1, 1, 3, 3});
table.setTotalWidth(width);
// table body
for (int r = 0; r < rows;) {
table.addCell(String.valueOf(++r));
table.addCell("1");
table.addCell("text");
table.addCell("10.0");
cell = new PdfPCell(new Phrase("10.0"));
cell.setCellEvent(new SubTotalEvent(totals, 10));
table.addCell(cell);
}
// extra footer
PdfPTable total = new PdfPTable(5);
total.setWidths(new int[]{1, 1, 1, 3, 3});
total.setTotalWidth(width);
cell = new PdfPCell(new Phrase("Total (excl. vat)"));
cell.setColspan(4);
total.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new SubTotal3.SubTotalEvent(totals));
total.addCell(cell);
cell = new PdfPCell(new Phrase("VAT"));
cell.setColspan(4);
total.addCell(cell);
total.addCell("15%");
cell = new PdfPCell(new Phrase("Total (incl. vat)"));
cell.setColspan(4);
total.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new SubTotal3.SubTotalEvent(totals));
total.addCell(cell);
PdfContentByte cb = writer.getDirectContent();
float availableHeight = document.top() - document.bottom()
- footer.getTotalHeight() - footer.getTotalHeight();
int start = 0;
float left = document.left();
float pos = document.top();
for (int i = 0; i < rows; ) {
pos = header.writeSelectedRows(0, -1, left, pos, cb);
float height = 0;
while (height < availableHeight && i < rows) {
height += table.getRowHeight(i++);
}
if (height >= availableHeight) i--;
pos = table.writeSelectedRows(start, i, left, pos, cb);
start = i;
height += total.getTotalHeight();
if (i == rows) {
if (height > availableHeight) {
footer.writeSelectedRows(0, -1, left, pos, cb);
document.newPage();
pos = document.top();
}
totals.done = true;
total.writeSelectedRows(0, -1, left, pos, cb);
}
else {
footer.writeSelectedRows(0, -1, left, pos, cb);
document.newPage();
pos = document.top();
}
}
document.close();
}
}
上一个回答:
这是我最终得到的代码。我分享它的价值:
package sandbox.tables;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPCellEvent;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class SubTotal2 {
public static final String DEST = "results/tables/subtotal2.pdf";
public static void main(String[] args) throws IOException,
DocumentException {
File file = new File(DEST);
file.getParentFile().mkdirs();
new SubTotal2().createPdf(DEST);
}
class Totals {
double subtotal = 0;
double total = 0;
}
class SubTotalEvent implements PdfPCellEvent {
Double price;
Totals totals;
public SubTotalEvent(Totals totals, double price) {
this.totals = totals;
this.price = price;
}
public SubTotalEvent(Totals totals) {
this.totals = totals;
price = null;
}
@Override
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
if (price == null) {
PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
new Phrase(String.valueOf(totals.subtotal)),
position.getLeft() + 2, position.getBottom() + 2, 0);
totals.subtotal = 0;
return;
}
totals.subtotal += price;
totals.total += price;
}
}
public void createPdf(String dest) throws IOException, DocumentException {
Totals totals = new Totals();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
// actual table
PdfPTable table = new PdfPTable(5);
table.setWidths(new int[]{1, 1, 1, 3, 3});
// header
table.addCell("Pos");
table.addCell("Menge");
table.addCell("Text");
table.addCell("Einzerpreis");
table.addCell("Summe");
// definitions
table.setHeaderRows(1);
table.setComplete(false);
PdfPCell cell;
float threshold = 55;
// table body
for (int r = 0; r < 92;) {
table.addCell(String.valueOf(++r));
table.addCell("1");
table.addCell("text");
table.addCell("10.0");
cell = new PdfPCell(new Phrase("10.0"));
cell.setCellEvent(new SubTotalEvent(totals, 10));
table.addCell(cell);
document.add(table);
if (writer.getVerticalPosition(false) < threshold) {
cell = new PdfPCell(new Phrase("Subtotal"));
cell.setColspan(4);
table.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new SubTotal2.SubTotalEvent(totals));
table.addCell(cell);
}
}
// extra footer
PdfPTable tTable = new PdfPTable(5);
tTable.setKeepTogether(true);
tTable.setWidths(new int[]{1, 1, 1, 3, 3});
cell = new PdfPCell(new Phrase("Total (excl. vat)"));
cell.setColspan(4);
tTable.addCell(cell);
tTable.addCell(String.valueOf(totals.total));
cell = new PdfPCell(new Phrase("VAT"));
cell.setColspan(4);
tTable.addCell(cell);
tTable.addCell("15%");
cell = new PdfPCell(new Phrase("Total (incl. vat)"));
cell.setColspan(4);
tTable.addCell(cell);
tTable.addCell(String.valueOf(totals.total * 1.15));
tTable.setTotalWidth(table.getTotalWidth());
if (
writer.getVerticalPosition(false) >= threshold &&
writer.getVerticalPosition(false) < document.bottom() + tTable.getTotalHeight()) {
cell = new PdfPCell(new Phrase("Subtotal"));
cell.setColspan(4);
table.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new SubTotal2.SubTotalEvent(totals));
table.addCell(cell);
}
table.setComplete(true);
document.add(table);
document.add(tTable);
document.close();
}
}
此代码中有一些黑暗魔法:threshold
的值是经过反复试验确定的。它是一个Y位置,定义我们在哪个Y位置决定需要一个页脚。这不是一个完整的猜测:您可以获取底部边距的Y位置(36),添加单行的高度(16)并添加足够的空间,确保不超过您添加的底部边距两行的高度。
不要定义页脚,只需逐行添加表格,并检查每一行后的Y位置。如果达到阈值(writer.getVerticalPosition(false) < threshold
),请添加页脚。
现在我们每次接近页面末尾时都会添加页脚,但如果我们不接近底部边距,则不会添加页脚,但是足够接近以便需要新页面包含总计的表(writer.getVerticalPosition(false) >= threshold && writer.getVerticalPosition(false) < document.bottom() + tTable.getTotalHeight()
)。在这种情况下,我们还需要添加额外的页脚行。
您可以通过将值92
更改为89
,90
,91
,93
和94
来测试此示例。它有效,但它是棘手的代码。