我尝试在iText中绘制一些嵌套表,因为我认为这是放置所有内容的最简单方法。

java - 有人可以解释一下iTexts Canvas 的绘制顺序吗?-LMLPHP

所以我在另一个表中有多个表,这些表都具有背景颜色和/或笔触(通过PdfPCellEvents)。不幸的是,外部表的笔触与内部表的背景重叠。
我认为这是由于我的PdfPCellEvents中的应用顺序错误或设置的某些saveStaterestoreState错误。

谁能向我解释saveStaterestoreState的正确用法,并提示我如何正确使用背景和笔触?

这是我添加条纹背景单元格的代码:

PdfPCell scaleBackground = new PdfPCell();
scaleBackground.setBorder(Rectangle.NO_BORDER);
scaleBackground.setVerticalAlignment(Element.ALIGN_TOP);
scaleBackground.setCellEvent(new StripedScaleBackground(max, scaleHeight));


StripedScaleBackground的cellLayout方法:

public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvases)
{
    PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
    float llx = rect.getLeft();
    float lly = rect.getBottom();
    float urx = rect.getRight();
    float ury = rect.getTop();

    // Light scale lines with padding from left
    canvas.setLineWidth(Constants.BORDER_WIDTH_THIN);
    canvas.setColorStroke(Colors.LIGHT_GRAY);

    float paddingLeft = 22f;
    for (int i = 0; i <= this.maxValue; i++)
    {
        canvas.moveTo(llx + paddingLeft, lly + (this.scaleHeight * (i + 1)));
        canvas.lineTo(urx, lly + (this.scaleHeight * (i + 1)));
    }

    // Vertical line
    canvas.moveTo(llx + (((urx - llx) + paddingLeft) / 2), ury);
    canvas.lineTo(llx + (((urx - llx) + paddingLeft) / 2), lly);
    canvas.stroke();

    // Fat line left and right
    canvas.moveTo(llx, ury);
    canvas.lineTo(llx, lly);
    canvas.moveTo(urx, ury);
    canvas.lineTo(urx, lly);

    canvas.setLineWidth(0.8f);
    canvas.setColorStroke(Colors.MEDIUM_GRAY);
    canvas.stroke();

    canvas.saveState();
    canvas.restoreState();
}


条形图是表格,其中每个单元格都有一个用于渐变和边框的单元格事件。条形图被添加到第一段代码的scaleBackground PdfPCell中,并具有以下PdfPCellEvents(图表黑色部分的示例):

public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvases)
{
    PdfContentByte backgroundCanvas = canvases[PdfPTable.BACKGROUNDCANVAS];
    float llx = rect.getLeft();
    float lly = rect.getBottom();
    float urx = rect.getRight();
    float ury = rect.getTop();

    // Draw background

    // Define shading with direction and color
    PdfShading shading = PdfShading.simpleAxial(this.writer,
                    llx, ury,
                    llx, lly,
                    Colors.BAR_CHART_BLACK_LIGHT, Colors.BAR_CHART_BLACK_DARK);

    PdfShadingPattern pattern = new PdfShadingPattern(shading);
    backgroundCanvas.setShadingFill(pattern);

    // Draw shape with defined shading
    backgroundCanvas.moveTo(llx, ury);
    backgroundCanvas.lineTo(llx, lly);
    backgroundCanvas.lineTo(urx, lly);
    backgroundCanvas.lineTo(urx, ury);
    backgroundCanvas.lineTo(llx, ury);
    backgroundCanvas.fill();

    backgroundCanvas.saveState();
    backgroundCanvas.restoreState();

    // Draw border
    PdfContentByte lineCanvas = canvases[PdfPTable.LINECANVAS];

    float lineWidth = Constants.BORDER_WIDTH_THIN;
    lineCanvas.setLineWidth(lineWidth);
    lineCanvas.moveTo(llx, ury - lineWidth);
    lineCanvas.lineTo(llx, lly);
    lineCanvas.lineTo(urx, lly);
    lineCanvas.lineTo(urx, ury - lineWidth);

    lineCanvas.setColorStroke(BaseColor.BLACK);
    lineCanvas.stroke();

    lineCanvas.saveState();
    lineCanvas.restoreState();
}

最佳答案

这是不同直接内容层的顺序:


PdfPtable.BASECANVAS-此处放置的所有物品均在桌子下方。
PdfPtable.BACKGROUNDCANVAS-这是背景所在的图层
画。
PdfPtable.LINECANVAS-这是绘制线条的图层。
PdfPtable.TEXTCANVAS-这是文本所在的图层。放任何东西
这将覆盖桌子。


摘自《 iText in Action-Second Edition》一书。

您还会询问saveState()restoreState()Chapter 2 of the iText 7 tutorial中对此进行了说明:


  首先,使用saveState()方法保存当前图形状态,然后更改状态并绘制要绘制的线条或形状,最后使用restoreState()方法返回到原始图形状态。在saveState()之后应用的所有更改都将被撤消。如果您更改多个值(线宽,颜色等),或者难以计算反向变化(返回至原始坐标系),则这尤其有趣。


您的代码对我来说太长了,无法检查,但是我高度怀疑 / saveState()是否会引起您的问题。

我会尽量避免嵌套表格。通常,使用colspan和rowpan更加容易(并且效率更高)。

如果这不能解决您的问题,请用一句话解释您的问题。

关于java - 有人可以解释一下iTexts Canvas 的绘制顺序吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37389019/

10-08 23:39