当我尝试创建虚线单元格时,我正在使用example中所述的PdfPCellEvent
。但是我得到了用虚线绘制的所有边框。当我设置cell.setBorder(Rectangle.BOTTOM | Rectangle.RIGHT);
底部和右边用实线绘制。当我删除setBorder时,我将所有边框都点缀起来。
答案 0 :(得分:2)
我认为你正在混淆事情。
如果您使用单元格事件绘制边框,则创建自定义边框,您应删除所有自动边框。所以你总是需要:
cell.setBorder(PdfPCell.NO_BORDER);
如果要绘制部分边框,则需要绘制部分边框。
在您引用的示例中,您使用moveTo()
,lineTo()
和stroke()
命令序列添加了许多行。换句话说:你决定绘制哪些行。
当你是画线的时候,很难理解为什么你会抱怨你“画出所有的边框”。如果要减少绘制的边框数,请绘制较少的线条。
你应该省略哪一行?这不是我们自己决定的:你知道你需要什么;你应该决定!
请查看DottedLineCell2示例。这是您所引用示例的变体。在此示例中,我创建了一个分别绘制每个边框的事件:
class DottedCell implements PdfPCellEvent {
private int border = 0;
public DottedCell(int border) {
this.border = border;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
canvas.saveState();
canvas.setLineDash(0, 4, 2);
if ((border & PdfPCell.TOP) == PdfPCell.TOP) {
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getLeft(), position.getTop());
}
if ((border & PdfPCell.BOTTOM) == PdfPCell.BOTTOM) {
canvas.moveTo(position.getRight(), position.getBottom());
canvas.lineTo(position.getLeft(), position.getBottom());
}
if ((border & PdfPCell.RIGHT) == PdfPCell.RIGHT) {
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getRight(), position.getBottom());
}
if ((border & PdfPCell.LEFT) == PdfPCell.LEFT) {
canvas.moveTo(position.getLeft(), position.getTop());
canvas.lineTo(position.getLeft(), position.getBottom());
}
canvas.stroke();
canvas.restoreState();
}
}
创建此事件的实例时,您必须传递border
值。在cellLayout()
方法中,我们将查看此边框值:
TOP
位时,我们构建一条从右上角到左上角的线,BOTTOM
位时,我们构建一条从右下角到左下角的线,RIGHT
位时,我们构建一条从右上角到右下角的线,LEFT
位时,我们会从左上角到左下角构建一条线。一旦我们检查了边框的所有边,我们stroke()
就行了。
在以下示例中,我创建了两个表:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
PdfPTable table;
PdfPCell cell;
table = new PdfPTable(4);
table.setSpacingAfter(30);
cell = new PdfPCell(new Phrase("left border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.LEFT));
table.addCell(cell);
cell = new PdfPCell(new Phrase("right border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.RIGHT));
table.addCell(cell);
cell = new PdfPCell(new Phrase("top border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.TOP));
table.addCell(cell);
cell = new PdfPCell(new Phrase("bottom border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.BOTTOM));
table.addCell(cell);
document.add(table);
table = new PdfPTable(4);
table.setSpacingAfter(30);
cell = new PdfPCell(new Phrase("left and top border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.LEFT | PdfPCell.TOP));
table.addCell(cell);
cell = new PdfPCell(new Phrase("right and bottom border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.RIGHT | PdfPCell.BOTTOM));
table.addCell(cell);
cell = new PdfPCell(new Phrase("no border"));
cell.setBorder(PdfPCell.NO_BORDER);
table.addCell(cell);
cell = new PdfPCell(new Phrase("full border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new DottedCell(PdfPCell.BOX));
table.addCell(cell);
document.add(table);
document.close();
}
这两个表格如下:dotted_line_cell2.pdf
更新2
在你的评论中,你声称我的答案是不够的,解释说你的编程技巧相当有限:你不能将单元格事件调整为绘制不同类型边框的事件。关于我最初的例子,你也问“这是唯一的方法吗?”
当然,这不是唯一的方法:有许多不同的方式来达到你想要的结果。请允许我提出两个额外的例子(尽管有更多可能的变体,其中一些可能涉及表事件而不是单元格事件):
额外示例#1:使用界面定义行短划线:
在CustomBorder3示例中,我复制/粘贴了上一个示例中的单元格事件,并按照以下方式对其进行了修改:
class CustomBorder implements PdfPCellEvent {
protected LineDash left;
protected LineDash right;
protected LineDash top;
protected LineDash bottom;
public CustomBorder(LineDash left, LineDash right,
LineDash top, LineDash bottom) {
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
if (top != null) {
canvas.saveState();
top.applyLineDash(canvas);
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getLeft(), position.getTop());
canvas.stroke();
canvas.restoreState();
}
if (bottom != null) {
canvas.saveState();
bottom.applyLineDash(canvas);
canvas.moveTo(position.getRight(), position.getBottom());
canvas.lineTo(position.getLeft(), position.getBottom());
canvas.stroke();
canvas.restoreState();
}
if (right != null) {
canvas.saveState();
right.applyLineDash(canvas);
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getRight(), position.getBottom());
canvas.stroke();
canvas.restoreState();
}
if (left != null) {
canvas.saveState();
left.applyLineDash(canvas);
canvas.moveTo(position.getLeft(), position.getTop());
canvas.lineTo(position.getLeft(), position.getBottom());
canvas.stroke();
canvas.restoreState();
}
}
}
如您所见,我不再定义border
值,而是定义了四个值:left
,right
,top
和{{1} }。在bottom
方法中,我为每个与cellLayout()
不同的值绘制一条线。
变量属于null
类型。 LineDash
是一个具有单一方法的接口:
LineDash
我为这个界面创建了三个实现:
interface LineDash {
public void applyLineDash(PdfContentByte canvas);
}
您可以轻松创建新的实施,例如:
class SolidLine implements LineDash {
public void applyLineDash(PdfContentByte canvas) { }
}
class DottedLine implements LineDash {
public void applyLineDash(PdfContentByte canvas) {
canvas.setLineCap(PdfContentByte.LINE_CAP_ROUND);
canvas.setLineDash(0, 4, 2);
}
}
class DashedLine implements LineDash {
public void applyLineDash(PdfContentByte canvas) {
canvas.setLineDash(3, 3);
}
}
你甚至可以引入一种改变边框颜色和宽度的实现。
我现在可以像这样使用class DashedLine2 implements LineDash {
float unitsOn;
float phase;
public DashedLine2(float unitsOn, float phase) {
this.unitsOn = unitsOn;
this.phase = phase;
}
public void applyLineDash(PdfContentByte canvas) {
canvas.setLineDash(unitsOn, phase);
}
}
事件:
CustomBorder
结果如下:
额外示例#2:使用抽象类作为单元格事件的基础:
在CustomBorder4示例中,我复制/粘贴了上一个示例中的单元格事件,并按照以下方式对其进行了修改:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
PdfPTable table;
PdfPCell cell;
LineDash solid = new SolidLine();
LineDash dotted = new DottedLine();
LineDash dashed = new DashedLine();
table = new PdfPTable(4);
table.setSpacingAfter(30);
cell = new PdfPCell(new Phrase("dotted left border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(dotted, null, null, null));
table.addCell(cell);
cell = new PdfPCell(new Phrase("solid right border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(null, solid, null, null));
table.addCell(cell);
cell = new PdfPCell(new Phrase("dashed top border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(null, null, dashed, null));
table.addCell(cell);
cell = new PdfPCell(new Phrase("bottom border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(null, null, null, solid));
table.addCell(cell);
document.add(table);
table = new PdfPTable(4);
table.setSpacingAfter(30);
cell = new PdfPCell(new Phrase("dotted left and solid top border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(dotted, null, solid, null));
table.addCell(cell);
cell = new PdfPCell(new Phrase("dashed right and dashed bottom border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(null, dashed, null, dashed));
table.addCell(cell);
cell = new PdfPCell(new Phrase("no border"));
cell.setBorder(PdfPCell.NO_BORDER);
table.addCell(cell);
cell = new PdfPCell(new Phrase("full solid border"));
cell.setBorder(PdfPCell.NO_BORDER);
cell.setCellEvent(new CustomBorder(solid, solid, solid, solid));
table.addCell(cell);
document.add(table);
document.close();
}
这个类是抽象的,因为它包含一个未实现的方法。我现在可以像这样扩展这个抽象类:
abstract class CustomBorder implements PdfPCellEvent {
private int border = 0;
public CustomBorder(int border) {
this.border = border;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
canvas.saveState();
setLineDash(canvas);
if ((border & PdfPCell.TOP) == PdfPCell.TOP) {
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getLeft(), position.getTop());
}
if ((border & PdfPCell.BOTTOM) == PdfPCell.BOTTOM) {
canvas.moveTo(position.getRight(), position.getBottom());
canvas.lineTo(position.getLeft(), position.getBottom());
}
if ((border & PdfPCell.RIGHT) == PdfPCell.RIGHT) {
canvas.moveTo(position.getRight(), position.getTop());
canvas.lineTo(position.getRight(), position.getBottom());
}
if ((border & PdfPCell.LEFT) == PdfPCell.LEFT) {
canvas.moveTo(position.getLeft(), position.getTop());
canvas.lineTo(position.getLeft(), position.getBottom());
}
canvas.stroke();
canvas.restoreState();
}
public abstract void setLineDash(PdfContentByte canvas);
}
同样,我可以引入不同的参数来改变短划线图案,颜色,线宽等。但这是你可以轻松自己做的事情。
我现在有三种不同的细胞事件,我可以在不同细胞或同一细胞上使用:
class SolidBorder extends CustomBorder {
public SolidBorder(int border) { super(border); }
public void setLineDash(PdfContentByte canvas) {}
}
class DottedBorder extends CustomBorder {
public DottedBorder(int border) { super(border); }
public void setLineDash(PdfContentByte canvas) {
canvas.setLineCap(PdfContentByte.LINE_CAP_ROUND);
canvas.setLineDash(0, 4, 2);
}
}
class DashedBorder extends CustomBorder {
public DashedBorder(int border) { super(border); }
public void setLineDash(PdfContentByte canvas) {
canvas.setLineDash(3, 3);
}
}
结果如下:
这些只是 两个额外的例子。人们可以轻松写出更多内容。如果您有任何进一步的问题(例如:如何更改边框的颜色),请创建一个新问题并显示您编写的代码,解释为什么它没有为您提供您期望的结果。