簡體   English   中英

繪制表格的自定義邊框,在itext7中具有更大的靈活性

[英]Draw custom borders for table with more flexibility in itext7

以前我問過一個有關繪制自定義表格邊框的問題: 在itext7中為跨表格的表格繪制自定義邊框

答案提供了一種繪制自定義邊框的方法,但是它不允許影響完整的行或列線(例如,將其稍微傾斜),因為為每個單元格分別繪制了單元格邊框。

我想在表格邊框中添加一些隨機性,如以下屏幕截圖所示:

桌子邊框

這是我適用於適合單個頁面的表的代碼,但是如果表跨多個頁面,則該代碼將不再起作用:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);
        doc.add(new Paragraph("Table event"));
        Table table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth();
        table.setNextRenderer(new DottedLineTableRenderer(table, new Table.RowRange(0, 0)));
        String s ="";
        for(int i=0;i<35;i++){
        s+="\nTest";
         }
        table.addCell(new Cell().add(new Paragraph(s)).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("A2")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("A3")).setBorder(Border.NO_BORDER));


        doc.add(table);


        doc.close();

private class DottedLineTableRenderer extends TableRenderer {
    public DottedLineTableRenderer(Table modelElement, Table.RowRange rowRange) {
        super(modelElement, rowRange);
    }

    @Override
    public void drawChildren(DrawContext drawContext) {
        super.drawChildren(drawContext);
        PdfCanvas canvas = drawContext.getCanvas();
        int maxLineTo = 5;
        int minLineTo = 2;
        int lineToHorizontalLine = (int)(Math.random() * maxLineTo) + minLineTo;

        int maxSkewHor = 5;
        int minSkewHor = 2;
        int skewHorizontalLine = (int)(Math.random() * maxSkewHor) + minSkewHor;

        int maxVerticalLine = 5;
        int minVerticalLine = 2;
        int lineToVerticalLine = (int)(Math.random() * maxVerticalLine) + minVerticalLine;


        canvas.setLineWidth(2).setStrokeColor(new DeviceRgb(222, 27, 27));

        // first horizontal line
        CellRenderer[] cellRenderers = rows.get(0);
        canvas.moveTo(cellRenderers[0].getOccupiedArea().getBBox().getLeft()-lineToHorizontalLine,
                cellRenderers[0].getOccupiedArea().getBBox().getTop());
        canvas.lineTo(cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getRight()+lineToHorizontalLine,
                cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getTop());


        for (int i = 0; i < rows.size(); i++) {
            skewHorizontalLine = (int)(Math.random() * maxSkewHor) + minSkewHor;
            lineToHorizontalLine = (int)(Math.random() * maxLineTo) + minLineTo;
            cellRenderers = rows.get(i);
            // horizontal lines
            canvas.moveTo(cellRenderers[0].getOccupiedArea().getBBox().getX()-lineToHorizontalLine,
                    cellRenderers[0].getOccupiedArea().getBBox().getY()+skewHorizontalLine);
            canvas.lineTo(cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getRight()+lineToHorizontalLine,
                    cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getBottom());

            // first vertical line
            Rectangle cellRect = cellRenderers[0].getOccupiedArea().getBBox();
            canvas.moveTo(cellRect.getLeft(), cellRect.getBottom());

            canvas.lineTo(cellRect.getLeft(), cellRect.getTop()+lineToVerticalLine );

            // vertical lines
            for (int j = 0; j < cellRenderers.length; j++) {
                lineToVerticalLine = (int)(Math.random() * maxVerticalLine) + minVerticalLine;


                cellRect = cellRenderers[j].getOccupiedArea().getBBox();
                canvas.moveTo(cellRect.getRight(), cellRect.getBottom()-lineToVerticalLine);
                canvas.lineTo(cellRect.getRight(), cellRect.getTop()+lineToVerticalLine); //ячейки

            }
        }
        canvas.stroke();
    }
}

我想自己繪制自定義邊框:)

首先,我們需要正確地覆蓋渲染器,即,覆蓋getNextRenderer()方法。 當前, TableRenderer重寫存在很大問題,因為無法訪問TableRenderer的無參數構造函數,而其他構造函數執行一些更改狀態的隱式工作。 但是我們仍然可以使用以下代碼解決此問題:

@Override
public IRenderer getNextRenderer() {
    CustomTableRenderer nextTable = new CustomTableRenderer((Table) modelElement);
    nextTable.rows.clear();
    nextTable.rowRange = null;
    return nextTable;
}

免責聲明 :由於答案使用TableRenderer私有實現細節,因此將來可能無法使用。 在撰寫本文時,它與最新發布的版本7.1.6配合使用。 為此,您應該創建代碼的自定義派生。 也歡迎請求請求

如果我們看一下TableRenderer的實現,我們會看到該類包含heights代碼中的行 )和countedColumnWidth代碼中的行 )字段,這聽起來很有趣,但它們是private 這意味着我們應該創建iText的自定義派生(源代碼可從https://github.com/itext/itext7獲得 ), protected這些字段並在我們的子類中使用它們。

你可以在你的代碼,而不是您自己的風險使用反射,但它不應該被使用,因為它可能無法與您的JVM工作(改變訪問修飾符是強烈反對),或者可能不會在iText的下一個版本的工作,或者可能無法正常工作由於另一個原因。 我不會在答案中添加反射代碼以進一步阻止其使用。

我們需要做的就是覆蓋drawBorders()方法。 這是已經為行添加一些隨機性的代碼。

private static class CustomTableRenderer extends TableRenderer {
    public CustomTableRenderer(Table modelElement) {
        super(modelElement);
    }

    @Override
    public IRenderer getNextRenderer() {
        CustomTableRenderer nextTable = new CustomTableRenderer((Table) modelElement);
        nextTable.rows.clear();
        nextTable.rowRange = null;
        return nextTable;
    }

    @Override
    protected void drawBorders(DrawContext drawContext) {
        PdfCanvas canvas = drawContext.getCanvas();
        canvas.saveState();
        canvas.setStrokeColor(ColorConstants.RED);

        Random r = new Random();

        // Draw vertical lines
        float curX = getOccupiedAreaBBox().getLeft();
        for (int i = 0; i <= countedColumnWidth.length; i++) {
            canvas.moveTo(curX, getOccupiedAreaBBox().getTop() + 3);
            canvas.lineTo(curX + r.nextInt(4), getOccupiedAreaBBox().getBottom() - 3);
            if (i < countedColumnWidth.length) {
                float curWidth = countedColumnWidth[i];
                curX += curWidth;
            }
        }

        // Draw horizontal lines
        float curY = getOccupiedAreaBBox().getBottom();
        for (int i = 0; i <= heights.size(); i++) {
            canvas.moveTo(getOccupiedAreaBBox().getLeft() - 3, curY);
            canvas.lineTo(getOccupiedAreaBBox().getRight() + 3, curY + r.nextInt(4));
            if (i < heights.size()) {
                float curHeight = heights.get(i);
                curY += curHeight;
            }
        }

        canvas.stroke();
        canvas.restoreState();
    }
}

要激活自定義渲染器,請在添加到文檔之前將其設置為表:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
Document doc = new Document(pdfDoc);

Table table = new Table(UnitValue.createPercentArray(new float[]{30, 30}));
for (int i = 0; i < 40; i++) {
    table.addCell(new Cell().add(new Paragraph("Hello")));
    table.addCell(new Cell().add(new Paragraph("World")));
    table.startNewRow();
}
table.setNextRenderer(new CustomTableRenderer(table));
doc.add(table);

結果表如下所示:

結果

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM