Fakhryan Albar
Fakhryan Albar

Reputation: 113

Get absolute width from PdfPTable column (iText)

How to get the absolute width of a column from iText when table columns are specified with their relative size ?

What I tried

I specified 3 columns with their relative width as float like this:

PdfPCell cell2;
PdfPTable table2 =  new PdfPTable(new float[]{(float) 4.5, (float) 0.5, 9});
table2.setWidthPercentage(100);

What I got

I tried to use table2.getAbsoluteWidths()[2] but result is float 0.0.

What I expected

I want to get the absolute width (which got maximized) for every column, after table width has been calculated dynamically on the PDF.

----------------------- EDIT ----------------------

Actually i need width of a column before document added and then replace my hardcode float variable restriction.

I Have many data String and wanna set in another column when get maximum width page with splitting in function restrictWidthOfFont

String fullAlamatPP = "test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test ";

float restrictions = (float) 330.12103; // this is width of a column from table

String alamatSesuaiKtpPP[] = restrictWidthOfFont(fullAlamatPP, font_body, restrictions);

Phrase p_alamat1_ct = new Phrase(alamatSesuaiKtpPP[0], font_body);
p_alamat1_ct.add(dottedline);
cell2 = new PdfPCell(p_alamat1_ct);
cell2.setBorder(PdfPCell.NO_BORDER);
table2.addCell(cell2);

Phrase p_alamat2_ct = new Phrase(alamatSesuaiKtpPP[1], font_body);
p_alamat2_ct.add(dottedline);
cell2 = new PdfPCell(p_alamat2_ct);
cell2.setBorder(PdfPCell.NO_BORDER);
table2.addCell(cell2);    

private static String[] restrictWidthOfFont(String character, Font font, float restrictions) {
        String results[];
        results = new String[] {"",""};
        String concatChar = " ";
        float widthOfString = 0;
        for (int i = 0; i < character.length();i++) {
            concatChar += character.charAt(i); 
            widthOfString = font.getCalculatedBaseFont(true).getWidthPoint(concatChar, font.getCalculatedSize());
//                System.out.println("widthOfString " + widthOfString);
            if (widthOfString > restrictions) {
                results[0] = concatChar.substring(0, concatChar.length() - 1);
                results[1] = character.substring(i, character.length());
                break;
            }
        }

        if (results[0] == "") {
            results[0] = character;
        }
        return results;
}    

that possible get width of a column before table document added?

Upvotes: 1

Views: 2166

Answers (1)

hc_dev
hc_dev

Reputation: 9377

Issue and explanation

The function table.getAbsoluteWidths() relies on the requirement that totalWidth of the table must be set, hence table.getTotalWidth() > 0.

This is because inside the com.itextpdf.text.pdf.PdfPTable class a method calculateWidths() is called which then calculates the absolute-widths of all columns:

this.absoluteWidths[k] = this.totalWidth * this.relativeWidths[k] / total;

Solution

In order to make sure that the totalWidth is set before you retrieve the relativeWidths array, you need to:

  • either (A) set the totalWidth like described in this answer
  • or (B) add cells to the table & add the table to the document

Code for solution

The following code incorporates your algorithm to split text (i.e. a long address or alamat) across cells based on the restriction of max width of a column:

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class TableWidthSample {

    public static void main(String[] args) {
        Document document = new Document();
        try {
            PdfWriter.getInstance(document, new FileOutputStream("TableColumnWidth.pdf"));
            document.open();

            PdfPTable table = createTableWithRelativeColumnWidths();

            // needed for calculation of getAbsoluteWidths: (A) totalWidth is set for table
            table.setTotalWidth(calculateTableWidthBasedOnPageA4(document, table));
            // now it prints width, because (A)
            printTableWidth(table, "after totalWidth set manually"); // absoluteWidths: [134.4857, 14.942857, 268.9714]

            // long text, that needs to be split among cells (fullAlamatPP)
            String text = "this is a very long text. The text contains a full address. Because the text is too long to be shown in the last cell, it is split.";
            // your CODE to fill text into cells based on restrictions
            addTextAcrossTableCells(table, text);

            document.add(table);

/*
            // need to add filled table to doc (B)
            addToDocumentCellsAndTable(document, table);
            // now it prints width, because (B)
            printTableWidth(table, "after added to doc"); // absoluteWidths: [134.4857, 14.942857, 268.9714]
*/
            document.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static PdfPTable createTableWithRelativeColumnWidths() {
        float[] relativeWidths = {4.5F, 0.5F, 9F};
        PdfPTable table = new PdfPTable(relativeWidths);
        table.setWidthPercentage(100F);
        printTableWidth(table, "after table created"); // absoluteWidths: [0.0, 0.0, 0.0]
        return table;
    }

    private static float calculateTableWidthBasedOnPageA4(Document document, PdfPTable table) {
        return (PageSize.A4.getWidth() - document.leftMargin() - document.rightMargin())
                * table.getWidthPercentage() / 100;
    }

    private static void addToDocumentCellsAndTable(Document document, PdfPTable table) throws DocumentException {
        // needed for calculation of getAbsoluteWidths: (B.1) add cells to table
        table.addCell("Hello");
        table.addCell("World");
        table.addCell("!");
        printTableWidth(table, "after cells added to table"); // absoluteWidths: [0.0, 0.0, 0.0]

        // needed for calculation of getAbsoluteWidths: (B.2) add table to doc
        document.add(table);
    }

    private static void addTextAcrossTableCells(PdfPTable table, String text) throws IOException, DocumentException {
        // restrictions; this is width of a column from table
        float maxColumnWidth = table.getAbsoluteWidths()[2]; // 330.12103F;
        System.out.println("use width of third column as max: " + maxColumnWidth);
        // sample font used for calculation of text-width
        Font font = new Font(BaseFont.createFont("Courier", BaseFont.CP1250, true), 12);

        // alamatSesuaiKtpPP
        String splitText[] = getTextPartsUsingFontWithMaxWidth(text, font, maxColumnWidth);
        String dottedLine = "..";
        table.addCell("Alamat / Address:");

        // p_alamat1_ct
        Phrase phrase1 = new Phrase(splitText[0], font);
        phrase1.add(dottedLine);
        PdfPCell cell1 = new PdfPCell(phrase1);
        cell1.setBackgroundColor(BaseColor.LIGHT_GRAY);
        cell1.setBorder(PdfPCell.NO_BORDER);
        table.addCell(cell1);

        // p_alamat2_ct
        Phrase phrase2 = new Phrase(splitText[1], font);
        phrase2.add(dottedLine);
        PdfPCell cell2 = new PdfPCell(phrase2);
        cell2.setBorder(PdfPCell.NO_BORDER);
        table.addCell(cell2);
    }

    private static String[] getTextPartsUsingFontWithMaxWidth(String text, Font font, float maxWidth) {
        String results[] = new String[] {"",""};
        String firstPartOfText = " ";
        float widthOfText = 0;
        for (int i = 0; i < text.length();i++) {
            firstPartOfText += text.charAt(i);
            widthOfText = font.getCalculatedBaseFont(true).getWidthPoint(firstPartOfText, font.getCalculatedSize());
            System.out.printf("%d: widthOfText: %f\n", i, widthOfText);
            if (widthOfText > maxWidth) {
                results[0] = firstPartOfText.substring(0, firstPartOfText.length() - 1);
                results[1] = text.substring(i); // second argument "text.length()" is not needed
                break;
            }
        }

        if (results[0] == "") {
            results[0] = text;
        }
        return results;
    }

    private static void printTableWidth(PdfPTable table, String labelText) {
        float[] absoluteWidths = table.getAbsoluteWidths();
        System.out.println(labelText + "> getAbsoluteWidths: " + Arrays.toString(absoluteWidths));
    }
}

See also

How to make PdfPTable calculate column-width dynamically

Upvotes: 2

Related Questions