[reportlab-users] RE: Page Totals

CLIFFORD ILKAY reportlab-users@reportlab.com
Wed, 25 Aug 2004 07:15:13 -0400


Hello Henning,

At 08:52 AM 25/08/2004 +0200, Henning von Bargen wrote:
>What do you mean with "Page Totals"?

I mean totals for a given column in a table for the page, as opposed to the=
=20
whole report. e.g. if you have a report where you have subtotals on each=20
page for some column, I refer to that, as do many of the report generators=
=20
that I have seen, as a page total.

In this particular case, I have a column in a table that is displayed on=20
each page called "Amount Due". I want a subtotal at the bottom of each page=
=20
for that column and a grand total at the end of the report. I guess this=20
would be done with afterPage(), as per your example below. So mine would=20
look something like:

def afterPage(self):
         subtotal =3D subtotal + amountDue

I am not sure how subtotal actually gets placed on the page footer though.

Similarly, I want a variable called expiryDate, which can change many times=
=20
during the report, placed on the page header on every page. I think this is=
=20
what I have to do:

def beforePage(self, xpiry):
         expiryDate =3D xpiry

Again, I am not sure how beforePage is going to be invoked so that I can=20
pass expiryDate to it from my main method and I am not sure how expiryDate=
=20
is going to appear on the page header.

>I can give you an example how to
>output "Page X of Y" on each page.

Thank you.

>You'll have to create your subclasses of PageTemplate and BaseDocTemplate,
>then use doc.multibuild() with 2 passes to
>count the total number of pages first,
>then build once again, this time with the correct number of pages.
>
>There may be other ways to achieve this, but this works.
>
>It's a pity that one cannot use Platypus in the page headers/footers,
>it would certainly simplify the task.

Yes, that would help.

>HTH
>Henning
>
>#!/bin/env python
># -*- coding: iso-8859-1 -*-
>#
>#Copyright Triestram&Partner GmbH 2003
>#
># @AUTHOR Henning von Bargen
>#
># @SINCE  13.10.2003
>#
># @VERSION 0.1  $$ Revision                     $$
>#
>
>__version__=3D''' $$ Revision                     $$ '''
>
>__doc__=3D"""Vorlage f=FCr Tabellarische Berichte.
>
>Die hier definierten Klassen definieren das grunds=E4tzliche Layout
>der Berichte (z.B. Kopf- und Fusszeilen).
>"""
>
>from reportlab.platypus import PageTemplate, BaseDocTemplate, Frame,
>Paragraph
>from reportlab.platypus import Spacer, SimpleDocTemplate, TableStyle
>
>from reportlab.lib.units import inch,cm,mm
>from reportlab.lib import colors
>from reportlab.lib import pagesizes
>from reportlab.lib.styles import getSampleStyleSheet
>
>import os.path
>
>imagePath=3D"../images"
>
>class EinspaltigTemplate(PageTemplate):
>     def __init__(self, id, pageSize):
>         self.numPages =3D 0
>         self.pageWidth =3D pageSize[0]
>         self.pageHeight =3D pageSize[1]
>
>         # Seitenrand links/rechts 2cm, oben 2cm, unten 1.5cm,
>         frame1 =3D Frame(20*mm,
>                        15*mm,
>                        self.pageWidth - 40*mm,
>                        self.pageHeight - 35*mm, id=3D'normal')
>         PageTemplate.__init__(self, id, [frame1])  # note lack of onPage
>
>     def afterDrawPage(self, canvas, doc):
>         # Titel und Seitenzahl in der Kopfzeile ausgeben
>         y =3D self.pageHeight - 15*mm
>         canvas.saveState()
>         canvas.drawImage(os.path.join(imagePath,'mylogo.jpg'),20*mm,
>self.pageHeight-14*mm)
>         canvas.setFont('Helvetica', 12)
>         canvas.drawString(60*mm, y+8, "My document title")
>         canvas.line(20*mm, y, self.pageWidth - 20*mm, y)
>         canvas.setFont('Helvetica', 8)
>         canvas.drawRightString(self.pageWidth - 20*mm, y+8, "Page %(page)d
>of %(numpages)d" % { "page":canvas.getPageNumber(),
>"numpages":doc.numPages})
>         canvas.restoreState()
>
>class StandardDocTemplate(BaseDocTemplate):
>     """Hier wird das Standardlayout definiert.
>
>        Bemerkenswert bei diesem DocTemplate ist, dass die Gesamtseitenzahl
>berechnet wird
>        und in der Kopzeile ausgegeben werden kann.
>
>        Sauberer w=E4re es eigentlich, ein IndexingFlowable zu verwenden,
>        dass als allerletztes Element hinzugef=FCgt wird.
>     """
>
>     def progresshandler(self, what, arg):
>         if what in ["PASS", "PAGE"]:
>             print what, arg
>         #print "numPages=3D%d" % self.numPages
>         if what=3D=3D'STARTED':
>             self._lastnumPages =3D self.numPages
>
>     def afterInit(self):
>         # Standard: ohne Deckblatt
>         self.addPageTemplates(EinspaltigTemplate('Einspaltig',
>self.pagesize))
>
>         #just playing
>         self.numPages =3D 1
>         self._lastnumPages =3D 0
>         self.setProgressCallBack(self.progresshandler)
>
>     def afterPage(self):
>         """This is called after page processing, and
>         immediately after the afterDrawPage method
>         of the current page template."""
>         self.numPages =3D max(self.canv.getPageNumber(), self.numPages)
>
>     def _allSatisfied(self):
>         """Eine unsaubere Implementierung, aber bevor wir jetzt anfangen=
 mit
>Cross-Referenzen etc.
>            machen wir es lieber so.
>            Called by multi-build - are all cross-references resolved?
>         """
>         if self._lastnumPages < self.numPages:
>             return 0
>         return BaseDocTemplate._allSatisfied(self)

Regards,

Clifford Ilkay
Dinamis Corporation
3266 Yonge Street, Suite 1419
Toronto, Ontario
Canada M4N 3P6

Tel: 416-410-3326=20