2017-02-03 6 views
1

Я пытаюсь создать динамический заголовок страницы с помощью itext7 с помощью EventHandlers. Я использую следующий код для этого:Проблема с динамическим заголовком iText 7

public static void main(String[] args) throws Exception { 
    File file = new File("C:\\Test\\variable_header.pdf"); 
    file.getParentFile().mkdirs(); 
    new VariableHeader().manipulatePdf(DEST); 
} 

protected void manipulatePdf(String dest) throws Exception { 
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST)); 
    Document doc = new Document(pdfDoc); 
    VariableHeaderEventHandler handler = new VariableHeaderEventHandler(); 
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, handler); 
    handler.setHeader("First Header"); 
    for (int i = 1; i <= 50; i++) { 
     doc.add(new Paragraph("Added First content")); 
    } 
    doc.add(new AreaBreak()); 
    handler.setHeader("Second Header"); 
    for (int i = 1; i <= 15; i++) { 
     doc.add(new Paragraph("Added Second content")); 
    } 
    doc.close(); 
} 

protected class VariableHeaderEventHandler implements IEventHandler { 
    protected String header; 

    public void setHeader(String header) { 
     this.header = header; 
    } 

    @Override 
    public void handleEvent(Event event) { 
     PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; 
     try { 
      new PdfCanvas(documentEvent.getPage()) 
        .beginText() 
        .setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 12) 
        .moveText(450, 806) 
        .showText(header) 
        .endText() 
        .stroke(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

Здесь я создал «VariableHeaderEventHandler», который отображает динамический заголовок страницы для каждой страницы документа.

Первоначально я задал заголовок страницы как «Первый заголовок» и добавил текст «Добавлен первый контент» в документ 50 раз. Затем я добавил Разрыв области, который оставляет оставшуюся часть страницы пустой после рендеринга предыдущего содержимого, и любое другое содержимое будет отображаться на новой странице. Затем я изменил заголовок страницы как «Второй заголовок» и добавил текст «Добавлено второе содержимое» в документ в 15 раз.

В соответствии с приведенным выше кодом заголовок страницы «Второй заголовок» должен отображаться ТОЛЬКО со страницы, на которой отображается текст «Добавлено второе содержимое». Но «Второй заголовок» оказываются на предыдущей странице, где текст «добавлено первое содержание» отображаются, как показано ниже:

iText7 Динамический вопрос заголовка:

Screenshot

Похоже, есть некоторые проблема с механизмом обработки событий в iText 7.0.1.

Есть ли способ решить эту проблему? Любая помощь будет оценена по достоинству.

ответ

1

Вы используете низкоуровневые события PdfDocument вместе с высокоуровневой компоновкой через Document. END_PAGE Событие запускается, когда страница выгружается в выходной поток. Хотя низкоуровневые PdfDocument и высокоуровневые Document связаны, нет контракта, что Document сбрасывает страницу сразу после ее перехода на новую. Фактически, Document выполняет флеш-страницы с некоторой задержкой по умолчанию, которая требуется более мелкомасштабными возможностями макета. Тот факт, что страницы сбрасываются с некоторой задержкой, вызывает появление вновь заданного заголовка на более старых страницах с содержимым первого типа. Так что это ожидаемое поведение, по крайней мере на данный момент.

Существует множество способов обойти это поведение и достичь того, чего вы хотите. Я расскажу об одном из них.

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

doc.add(new AreaBreak()); 
int secondContentStartPageNumber = doc.getRenderer().getCurrentArea().getPageNumber(); 

Вы можете затем передать эту информацию в обработчик событий:

handler.setSecondAreaStartPage(secondContentStartPageNumber); 

и использовать эту информацию при выборе заголовка для вывода на странице:

int pageNumber = documentEvent.getDocument().getPageNumber(documentEvent.getPage()); 
String textToShow = pageNumber < secondAreaStartPage ? firstHeader : secondHeader; 

Полный VariableHeaderEventHandler класс будет выглядеть следующим образом:

protected class VariableHeaderEventHandler implements IEventHandler { 
    private String firstHeader = "First Header"; 
    private String secondHeader = "Second Header"; 
    private int secondAreaStartPage = Integer.MAX_VALUE; 

    public void setSecondAreaStartPage(int newValue) { 
     secondAreaStartPage = newValue; 
    } 

    @Override 
    public void handleEvent(Event event) { 
     PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; 
     int pageNumber = documentEvent.getDocument().getPageNumber(documentEvent.getPage()); 
     try { 
      new PdfCanvas(documentEvent.getPage()) 
        .beginText() 
        .setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 12) 
        .moveText(450, 806) 
        .showText(pageNumber < secondAreaStartPage ? firstHeader : secondHeader) 
        .endText() 
        .stroke(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Конечно, для случая более двух областей код станет более сложным, но это в большей степени программирования упражнений, чем вопрос о iText.

+0

Это сложнее, чем обычная реализация этой задачи. В частности, если вы хотите, чтобы текущая глава и раздел в верхнем или нижнем колонтитуле или что-то подобное динамически ... – mkl

Смежные вопросы