Я использую библиотеку PDFJet-Open-Source для создания PDF-файлов. Итак, у меня есть пара вопросов:

1) Как разместить многострочный текст внутри ячейки?

Описание проблемы. В настоящее время я столкнулся с проблемой, заключающейся в том, что я не могу разместить многострочный текст внутри объекта Cell. Я пробовал установить текст вроде "text1 \n text2...", но это не дало никакого эффекта. К сожалению, в версии с открытым исходным кодом нет классов TextColumn и Paragraph.

2) Что такое CompositeTextLine и как его использовать?

Описание проблемы. Возможно, у меня неправильное воображение, но я пытался сделать следующее:

...
CompositeTextLine ctl = new CompositTextLine(0,0);
ctl.addComponent(new TextLine(f1,"MyText1"));
ctl.addComponent(new TextLine(f1,"MyText2"));
ctl.addComponent(new TextLine(f1,"MyText3"));
Cell cell = new Cell(f1);
cell.setCompositeTextLine(ctl);
...

Я ожидал увидеть несколько строк в ячейке, но ничего не заметил. Более того, если я добавлю строку table.wrapAroundCellText(), у меня будет NullPointerException . Если я вызываю ctl.drawOn(page), я просто наблюдаю: «MyText1 MyText2 MyText3» без разрыва строки.

ОБНОВЛЕНИЕ: я обнаружил класс TextBox, поэтому, если я напишу:

TextBox textbox = new TextBox(f1);
textbox.setText("First Line \n Second Line");
textbox.drawOn(page);

Он построит то, что я хочу:

First Line
Second Line

Но все же меня интересует возможность (1) и описание (2) и некоторые из них варианты, например, «Как установить TextBox (или изображение и т. Д.) Внутри ячейки, а не только в одну строку?»

И последнее, не мог бы кто-нибудь направить меня к реализации алгоритма «выравнивания текста» на Java или C ++.

3
Sergey V. 9 Апр 2014 в 22:05

2 ответа

Лучший ответ

Я могу решить ту же проблему, и в итоге я расширил Cell и использовал WordUtils из apache commons lang3 :

public class MultilineCell extends Cell {

    private final int characterCount;

    public MultilineCell(Font font, String content, int characterCount) {
        super(font, content);
        this.characterCount = characterCount;
    }

    @Override
    public String getText() {
        return WrapUtil.wrap(super.getText(), this.characterCount);
    }

    @Override
    public float getHeight() {
        float height = this.font.getBodyHeight();

        String text = getText();
        if (text != null) {
            String[] wrappedTexts = text.split(System.getProperty("line.separator"));

            if (wrappedTexts.length > 1) {
                return (height * wrappedTexts.length) + this.top_padding + this.bottom_padding;
            }
        }
        return height + this.top_padding + this.bottom_padding;
    }

    @Override
    protected void paint(Page page, float x, float y, float w, float h) throws Exception {
        page.setPenColor(this.getPenColor());
        page.setPenWidth(this.lineWidth);

        drawBorders(page, x, y, w, h);
        drawText(page, x, y, w);
    }

    private void drawBorders(
            Page page,
            float x,
            float y,
            float cell_w,
            float cell_h) throws Exception {

        if (getBorder(Border.TOP) &&
                getBorder(Border.BOTTOM) &&
                getBorder(Border.LEFT) &&
                getBorder(Border.RIGHT)) {
            page.drawRect(x, y, cell_w, cell_h);
        }
        else {
            if (getBorder(Border.TOP)) {
                page.moveTo(x, y);
                page.lineTo(x + cell_w, y);
                page.strokePath();
            }
            if (getBorder(Border.BOTTOM)) {
                page.moveTo(x, y + cell_h);
                page.lineTo(x + cell_w, y + cell_h);
                page.strokePath();
            }
            if (getBorder(Border.LEFT)) {
                page.moveTo(x, y);
                page.lineTo(x, y + cell_h);
                page.strokePath();
            }
            if (getBorder(Border.RIGHT)) {
                page.moveTo(x + cell_w, y);
                page.lineTo(x + cell_w, y + cell_h);
                page.strokePath();
            }
        }

    }

    private void drawText(
            Page page,
            float x,
            float y,
            float cell_w) throws IOException {

        String wrappedText = WrapUtil.wrap(super.getText(), this.characterCount);
        String[] lines = wrappedText.split(System.getProperty("line.separator"));

        float x_text = x + this.left_padding;
        float y_text = y + this.font.getAscent() + this.top_padding;

        for (String line : lines) {
            page.drawString(this.font, line, x_text, y_text);
            y_text += this.font.getBodyHeight();
        }
    }
}

Вы можете создать и добавить MultilineCell так же, как и в случае с Cell:

List<Cell> rowCells = new ArrayList<Cell>();
rowCells.add(new MultilineCell(font, c.getString(reasonIdx), 42));

Я знаю, что расширение - плохое решение, а копирование drawBorders () еще хуже, но в данном случае это единственное решение, если вы не хотите форкнуть PDFJet.

Однако это нарушает autoAdjustColumnWidths: ширина рассчитывается по всему тексту, а не по самой длинной строке. Итак, если вы собираетесь использовать этот метод, либо подкласс Table, либо форк PDFJet, либо извлечение только этого метода (единственный недостаток последнего в том, что я не мог обойтись без заполнения ячеек):

/**
 * Auto adjusts the widths of all columns so that they are just wide enough to hold the text without truncation.
 */
private static void autoAdjustColumnWidths(List<List<Cell>> tableData) {
    // Find the maximum text width for each column
    float[] max_col_widths = new float[tableData.get(0).size()];
    for (int i = 0; i < tableData.size(); i++) {
        List<Cell> row = tableData.get(i);
        for (int j = 0; j < row.size(); j++) {
            Cell cell = row.get(j);
            if (cell.getColSpan() == 1) {
                float cellWidth = 0f;
                if (cell.getImage() != null) {
                    cellWidth = cell.getImage().getWidth();
                }
                if (cell.getText() != null) {
                    // Is this a multiline cell? If so, measure the widest line
                    if (cell.getText().contains(MultilineCell.NEW_LINE)) {
                        String[] lines = cell.getText().split(MultilineCell.NEW_LINE);
                        for (String line : lines) {
                            if (cell.getFont().stringWidth(cell.getFallbackFont(), line) > cellWidth) {
                                cellWidth = cell.getFont().stringWidth(cell.getFallbackFont(), line);
                            }
                        }
                    }
                    // Standard (single-line) cell, measure whole text
                    else {
                        if (cell.getFont().stringWidth(cell.getFallbackFont(), cell.getText()) > cellWidth) {
                            cellWidth = cell.getFont().stringWidth(cell.getFallbackFont(), cell.getText());
                        }
                    }
                }
                cell.setWidth(cellWidth + 2f /*cell.left_padding*/ + 2f/*cell.right_padding*/);
                if (max_col_widths[j] == 0f ||
                        cell.getWidth() > max_col_widths[j]) {
                    max_col_widths[j] = cell.getWidth();
                }
            }
        }
    }

    for (int i = 0; i < tableData.size(); i++) {
        List<Cell> row = tableData.get(i);
        for (int j = 0; j < row.size(); j++) {
            Cell cell = row.get(j);
            cell.setWidth(max_col_widths[j]);
        }
    }
}

PDFJet - забавная библиотека, кстати: защищенные поля, любой другой метод выдает исключение, и классы определенно не предназначены для расширения, даже если они не окончательные.

6
Benoit Duffez 30 Дек 2016 в 07:18

Для этого есть хитрое решение: как было предложено ранее, разделите ввод на несколько строк (например, используя WordUtils из apache commons lang3)

String wrappedText = WrapUtil.wrap(super.getText(), this.characterCount);
 String[] lines = wrappedText.split(System.getProperty("line.separator"));

После того, как у вас будет lines, добавьте столько строк, сколько строк в вашу таблицу с этими отдельными строками. Чтобы смоделировать "многострочную ячейку" вызовите функцию removeLineBetweenRows, предоставляющую индекс этих добавленных строк. Это будет выглядеть как одна большая ячейка.

0
Martin Ch 12 Фев 2015 в 10:43