Reputation: 41
I am working on an invoice and I would like to add a footer on the last page only (which can also be the first page).
Since the data of the table is dynamic, I am not able to calculate the number of pages.
Now I am working with 2 Page Templates, firstpage (with 2 frames and footer1) and nextpages (with 1 frame and footer2). This works when the data fills two pages, but when the table fills only 1 page or more then 2 pages, it no longer works.
I defined the footer in the following way:
footerFrame = Frame(x1=35*mm, y1=20*mm, width=175*mm, height=15*mm)
footerStory = [ Paragraph("Have a nice day.", styles["fancy"]) ]
def footer2(canvas,document):
canvas.saveState()
footerFrame.addFromList(footerStory, canvas)
canvas.restoreState()
Is there a more flexible way to define a footer, so it only shows up on the page at which the table ends?
Thanks in advance.
Upvotes: 3
Views: 1827
Reputation: 1391
By overriding ReportLabs canvas Class, you CAN keep track of the pages (granted I've done it with other reports that don't involve flowables, but I believe you can still make it work!) .
Since you are using a flowable (Paragraph), you need to know how many pages it is going to be with each new PDF generation (the length is the dynamic part). I am not 100% positive, but I think ReportLab's flowable still invoke the "showPage()" method of the canvas. So you can do the following:
In pseudo-code/part-python, I'd recommend the following (untested):
class MyFooterCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
## Subclass the ReportLab canvas class.
canvas.Canvas.__init__(self, *args, **kwargs)
## Create an empty list to store the saved pages so you can keep track of them.
self._savedPages = []
def showPage(self):
"""Override the showPage method"""
## We are writing our own showPage() method here, so we can keep track of
## what page we are on.
self._savedPages.append(self)
## Start a new page.
self._startPage()
def drawFooter(self):
"""Draws the footer to the page. You can have it do whatever you want here"""
self.drawString(50, 50, "This is my footer, yay me - footer freedom")
def save(self):
"""Saves the entire PDF in one go, a bit costly to do it this way,
but certainly one way to get a footer."""
numPages = len(self._savedPages)
for pages in self._savedPages:
## Finds the last page and when it 'hits', it will call the self.drawFooter() method.
if pages == self._savedPages[-1]:
self.drawFooter()
else:
## If it's not the last page, explicitly pass over it. Just being thorough here.
pass
## And... continue doing whatever canvas.Canvas() normally does when it saves.
canvas.Canvas.save(self)
AGAIN this is untested, but I think this will give you the behavior you want. Try it out, if you get stuck let me know, I can hash some of this out if need be, but I've done this same method for other non-flowables and it's worked for me in the past.
Upvotes: 4