Переключаться между ColumnDocumentRenderer и DocumentRenderer на одной странице?

Я тестировал несколько вещей с iText7, и у меня есть сценарий, в котором мне нужно иметь параграф DocumentRenderer вверху, а затем запустить ColumnDocumentRender с двумя столбцами прямо под ним на той же странице. Проблема, с которой я сталкиваюсь, заключается в том, что когда я меняю содержимое на той же странице, оно перекрывает содержимое из DocumentRenderer с содержимым из ColumnDocumentRenderer. Я считаю, что это потому, что один рендер не знает о другом рендере и содержимое начинается с верхней части страницы. Я следил за этот учебник, но он показывает только, как добавить контент на следующую страницу. Это говорит

we'll have to instruct iText not to flush the content to the OutputStream

Но может ли кто-нибудь показать мне, как именно этого добиться?

public void createPdf(String dest) throws IOException {
    PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
    Document document = new Document(pdf);
    Paragraph p = new Paragraph()
        .add("Be prepared to read a story about a London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde.");
    document.add(p);
    document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
    ... // Define column areas
    document.setRenderer(new ColumnDocumentRenderer(document, columns));
    document.add(new AreaBreak(AreaBreakType.LAST_PAGE));   
    ... // Add novel in two columns
    document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
    document.setRenderer(new DocumentRenderer(document)); 
    document.add(new AreaBreak(AreaBreakType.LAST_PAGE));
    p = new Paragraph()
        .add("This was the story about the London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde. THE END!");
    document.add(p);
    document.close();
}

Мне нужно что-то вроде этого:

Столбцы iText7

Whenever you create a new DocumentRenderer, iText starts returns to the top of the document –that is: from the first page. This allows you to use different renderers on the same document next to each other on the same page. If that is needed, we'll have to instruct iText not to flush the content to the OutputStream; otherwise we won't have access to previous pages. In this case, we don't need to change anything on previous pages. We just want to switch to another renderer on the next page. Introducing a page break that goes to the last page will avoid that new content overwrites old content.

Одно из решений, о котором я думаю сейчас, - это использовать ColumnDocumentRenderer повсюду и установить номер столбца как 1 вверху, а затем использовать номер столбца как 2 внизу. Я не знаю, поможет ли это, но просто думаю, возможно ли это.

comwiz756 28.06.2018 16:05

Я попытался воспроизвести вашу проблему, но либо я неправильно понял вопрос, либо не могу воспроизвести проблему. Прокомментируйте, пожалуйста, мой ответ.

Bruno Lowagie 28.06.2018 16:40

@BrunoLowagie какие-нибудь решения, которые я могу изучить? MultiColumnText помогал в старых версиях iText. i.stack.imgur.com/s53A0.png

comwiz756 28.06.2018 19:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
460
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я взял этот код: C02E08_JekyllHydeV4

И я обновил его в соответствии с тем, что вы указали в своем вопросе:

//Initialize PDF document
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
// Initialize document
Document document = new Document(pdf);
Paragraph p = new Paragraph()
    .add("Be prepared to read a story about a London lawyer "
       + "named Gabriel John Utterson who investigates strange "
       + "occurrences between his old friend, Dr. Henry Jekyll, "
       + "and the evil Edward Hyde.");
document.add(p);
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));

//Set column parameters
...
//Define column areas
...
document.setRenderer(new ColumnDocumentRenderer(document, columns)); 
document.add(new AreaBreak(AreaBreakType.LAST_PAGE));   
// Add the full Jekyl and Hyde text
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
document.setRenderer(new DocumentRenderer(document)); 
document.add(new AreaBreak(AreaBreakType.LAST_PAGE));
p = new Paragraph()
    .add("This was the story about the London lawyer "
       + "named Gabriel John Utterson who investigates strange "
       + "occurrences between his old friend, Dr. Henry Jekyll, "
       + "and the evil Edward Hyde. THE END!");
document.add(p);
//Close document
document.close();

Результат выглядит так:

Я думаю, это то поведение, которое вы ищете. Если нет, объясните, что пошло не так.

Обновлено:

После уточнения вопроса становится ясно, что приведенный выше ответ не решает проблему. Это решение актуальной проблемы:

Нам нужно создать собственный ParagraphRenderer для определения Y-позиции: class MyParagraphRenderer расширяет ParagraphRenderer {

    float y;

    public MyParagraphRenderer(Paragraph modelElement) {
        super(modelElement);
    }

    @Override
    public void drawBorder(DrawContext drawContext) {
        super.drawBorder(drawContext);
        y = getOccupiedAreaBBox().getBottom();
    }

    public float getY() {
        return y;
    }

}

Когда мы добавляем первый абзац, нам нужно использовать этот пользовательский ParagraphRenderer:

Paragraph p = new Paragraph()
        .add("Be prepared to read a story about a London lawyer "
        + "named Gabriel John Utterson who investigates strange "
        + "occurrences between his old friend, Dr. Henry Jekyll, "
        + "and the evil Edward Hyde.");
MyParagraphRenderer renderer = new MyParagraphRenderer(p);
p.setNextRenderer(renderer);
document.add(p);

Теперь мы можем получить нужную позицию Y следующим образом: renderer.getY(); мы используем эту позицию Y для определения первого набора столбцов:

float offSet = 36;
float gutter = 23;
float columnWidth = (PageSize.A4.getWidth() - offSet * 2) / 2 - gutter;
float columnHeight1 = renderer.getY() - offSet * 2;
Rectangle[] columns1 = {
    new Rectangle(offSet, offSet, columnWidth, columnHeight1),
    new Rectangle(offSet + columnWidth + gutter, offSet, columnWidth, columnHeight1)};

Мы могли бы использовать этот набор столбцов для создания ColumnDocumentRenderer, но если для рендеринга всего содержимого требуется более одной страницы, то смещение столбцов на второй странице будет неправильным, поэтому мы также создаем собственный ColumnDocumentRenderer:

class MyColumnDocumentRenderer extends ColumnDocumentRenderer {

    Rectangle[] columns2;

    public MyColumnDocumentRenderer(Document document, Rectangle[] columns1, Rectangle[] columns2) {
        super(document, columns1);
        this.columns2 = columns2;
    }

    @Override
    protected PageSize addNewPage(PageSize customPageSize) {
        PageSize size = super.addNewPage(customPageSize);
        columns = columns2;
        return size;
    }
}

Этот ColumnDocumentRenderer принимает два набора столбцов, один набор будет использоваться на первой странице, второй набор будет использоваться на всех последующих страницах. Вот как мы определяем и применяем собственный ColumnDocumentRenderer:

float columnHeight2 = PageSize.A4.getHeight() - offSet * 2;
Rectangle[] columns2 = {
    new Rectangle(offSet, offSet, columnWidth, columnHeight2),
    new Rectangle(offSet + columnWidth + gutter, offSet, columnWidth, columnHeight2)};
document.setRenderer(new MyColumnDocumentRenderer(document, columns1, columns2));  

Теперь результат выглядит так:

В зависимости от необходимого расстояния между первым абзацем на всей странице и последующим содержимым в столбцах вы можете настроить значение renderer.getY() - offSet * 2.

Спасибо, Бруно, за вашу помощь! :)

comwiz756 28.06.2018 16:55

Просто интересно, является ли сейчас ограничение самой библиотеки на достижение это? Или это выполнимо?

comwiz756 28.06.2018 17:45

Это выполнимо, но сейчас у меня нет времени отвечать. Часть решения можно найти здесь: developers.itextpdf.com/content/…

Bruno Lowagie 28.06.2018 20:18

хм, так что вы говорите, как только я добавляю абзац, получаю координаты x, y указателя курсора, а затем добавляю столбец, начинающийся с этой координаты?

comwiz756 28.06.2018 20:27

@ comwiz756 Я обновил свой ответ. Самый простой способ добиться этого - создать собственные средства визуализации. Если у вас есть только одна страница содержимого, вам может не понадобиться настраиваемое средство визуализации столбцов, но я все равно сделал его для полноты картины.

Bruno Lowagie 29.06.2018 10:16

это очень полезно. Спасибо. Думаю, было бы неплохо добавить это решение и в developers.itextpdf.com/content/itext-7-building-blocks/…. Очень помогло бы таким людям, как я. Еще раз спасибо!

comwiz756 29.06.2018 16:34

Другие вопросы по теме