Многострочный (параграф) нижний колонтитул и заголовок в ReportLab - PullRequest
16 голосов
/ 12 января 2012

Какой лучший способ иметь нижний колонтитул и заголовок в reportlab, а не просто одну строку, которую можно нарисовать с помощью canvas.drawString в функции onPage.Не нашел способа поместить что-то вроде Paragraph в верхний / нижний колонтитул в функции onPage.Каков наилучший способ справиться с этим?Есть ли способ поместить абзац в нижний колонтитул?

Ответы [ 4 ]

27 голосов
/ 14 августа 2012

Вы можете использовать произвольные команды рисования в функции onPage, поэтому вы можете просто нарисовать абзац (см. Раздел 5.3 в руководстве пользователя reportlab ) из вашей функции.

Вот полный пример:

from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Paragraph

styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']

def footer(canvas, doc):
    canvas.saveState()
    P = Paragraph("This is a multi-line footer.  It goes on every page.  " * 5,
                  styleN)
    w, h = P.wrap(doc.width, doc.bottomMargin)
    P.drawOn(canvas, doc.leftMargin, h)
    canvas.restoreState()

doc = BaseDocTemplate('test.pdf', pagesize=letter)
frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height,
               id='normal')
template = PageTemplate(id='test', frames=frame, onPage=footer)
doc.addPageTemplates([template])

text = []
for i in range(111):
    text.append(Paragraph("This is line %d." % i,
                          styleN))
doc.build(text)
9 голосов
/ 22 декабря 2015

Ответ Йохена великолепен, но я нашел его неполным. Он работает для нижних колонтитулов, но не для верхних колонтитулов, так как Reportlab будет рисовать все текущие элементы поверх верхнего колонтитула. Необходимо убедиться, что размер создаваемого фрейма исключает пространство, занимаемое заголовком, чтобы надписи заголовка не печатались поверх заголовка.

Используя код Йохена, вот полный пример для заголовков:

from reportlab.lib.pagesizes import letter, cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Paragraph
from functools import partial

styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']

def header(canvas, doc, content):
    canvas.saveState()
    w, h = content.wrap(doc.width, doc.topMargin)
    content.drawOn(canvas, doc.leftMargin, doc.height + doc.topMargin - h)
    canvas.restoreState()

doc = BaseDocTemplate('test.pdf', pagesize=letter)
frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height-2*cm, id='normal')
header_content = Paragraph("This is a multi-line header.  It goes on every page.  " * 8, styleN)
template = PageTemplate(id='test', frames=frame, onPage=partial(header, content=header_content))
doc.addPageTemplates([template])

text = []
for i in range(111):
    text.append(Paragraph("This is line %d." % i, styleN))
doc.build(text)

Обратите внимание на декляцию фрейма, он вычитает 2 см от высоты фрейма, чтобы освободить место для заголовка. Потоки будут напечатаны внутри фрейма, поэтому вы можете изменить размер фрейма, чтобы учесть различные размеры заголовков.

Я также нахожу, что мне обычно нужно передавать переменные в заголовок, поэтому я использовал частичную функцию, назначенную onPage, чтобы можно было передавать содержимое заголовка. Таким образом, вы можете иметь переменный заголовок на основе содержимого страницы.

1 голос
/ 27 февраля 2019

Дополнительный подход для добавления верхнего или нижнего колонтитула на всех страницах: для этого есть аргументы метода сборки.

Не используйте рамку и шаблон в ответе от Йохена. В последней строке используйте

doc.build(text, onFirstPage=footer, onLaterPages=footer)

Остальной подход будет таким же, как и у Йохена.

1 голос
/ 09 сентября 2016

Я знаю, что это немного устарело, но я столкнулся с этой проблемой и смог ее решить.Если у вас есть более одной страницы в вашем PDF и вы хотите иметь нижний колонтитул / верхний колонтитул на каждой странице, вы должны использовать NextPageTemplate('template_id').Я пишу только соответствующий код, так как остальное показано в примере @jochen выше.

В моем случае я использовал PageBreak(), и мне потребовалось некоторое время, чтобы понять, почему я получаю только нижний колонтитулпервая страница.

from reportlab.platypus import Paragraph, PageBreak, PageTemplate, Frame, NextPageTemplate

frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')
template = PageTemplate(id='footer', onPage=footer, frames=[frame])


# add a NextPageTemplate before a PageBreak to have the footer in the next page

text.append(Paragraph('some text', style)),
text.append(NextPageTemplate('footer')), # this will make the footer to be on the next page if exists
text.append(PageBreak())
doc.build(text)
...