Hilfe zum 1 x 1 für reportlab

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Was eine umständliche Formulierung ist für:

Code: Alles auswählen

BaseDocTemplate.__init__(self, filename, **kw)
Und natürlich steckt in "filename" auch keine Name, sondern ein Dateiobjekt ;-)

Edit: Code-Tags
Zuletzt geändert von EyDu am Dienstag 24. März 2015, 20:45, insgesamt 1-mal geändert.
Das Leben ist wie ein Tennisball.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die Zeile entstammt der Konvertierung mittels `2to3`. Beschwerden also bitte direkt an den Entwickler von `2to3` richten ;-)

Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,

jetzt funktioniert Dein Code, allerdings werden die Tabellendaten nicht in Tabellenform, sonder untereinander ausgegeben.

Was mich interessiert, damit ich Deinen Code verstehe:
- Wie funktioniert das, was auf die erste Seite passt.
- Und wenn der Inhalt größer als eine Seite ist.

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das Codebeispiel nimmt ja auch nur eine Liste von Strings und fügt diese dem Attribute "story" als normaler Paragraph mit dem Stil "BodyText" hinzu. Wenn du Bilder, Tabellen etc. einbauen willst, dann musst du die Funktion `build_story` entsprechend umschreiben.

Die Seitenumbrüche macht ReportLab automatisch. Was auf die Seite passt wird durch die Größe des Frames bestimmt. Hast du mehr Inhalt, dann wird automatisch die nächste Seite angelegt. Und jede Seite bekommt halt auch automatisch Kopf- und Fusszeile, dass erledigt das `onPage=self.buildHeadFoot`

Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

OK, bin nun schon ein gutes Stück weiter.

Nun möchte ich in einer Tabelle, die letzten 2 Spalten horizontal teilen.
Also nicht, wie mit SPAN zusammenführen, sondern das Gegenteil.
Die Tabelle hat 7 Spalten, davon sollen Spalte 6 und 7 geteilt werden.

Gibt es da eine Möglichkeit und wenn ja, welche?

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

lt. Doku keine.... Was du versuchen könntest:

* 2 Paragraphen in eine Zelle und schauen, ob das reicht
* die Zellen der die nicht geteilten Spalten span-en
* im Quellcode suchen, ob es eine nicht-dokumentierte Funktion dafür gibt. In der offiziellen Doku steht nämlich nicht unbeidngt alles drin...

Hier bei SO gibt's auch ein Beispiel mit Lösung, wie man das machen kann. Ist aber IMHO bei großen Tabellen unhandlich... http://stackoverflow.com/questions/1381 ... s-pdf-page

Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,

Danke für Deine Info.

Den Link habe ich schon mal gesehen, da ist aber der Aufwand zu groß, bis das so ist, wie es sein sollte.
Ist wohl, wie mit der Eierlegendenden Wollmilchsau ... :wink:

Lass das mal ruhen, vielleicht kommt mit etwas Abstand, eine Idee wie ich das noch umsetzen kann.

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Habe mich doch noch weiter mit der Thematik 'verändern der Tabellenstruktur mittels SPAN' beschäftigt und habe da evtl. eine Lösung auch für überlange Tabellen gefunden. :)

Bevor ich aber auf dieses Thema komme, benötige ich nochmals Hilfe zu noisefloorś gepostetem Code, der wirklich prima ist.

Beim Versuch, Daten als Tabelle ausgeben zu lassen, habe ich folgenden Abschnitt entsprechend geändert:

Code: Alles auswählen

    def build_story(self, text):
        #Frame definieren
        b, h = self.breite, self.hoehe
        f = Frame(1*cm, 2*cm, b - (2 * cm), h - (5.5 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='main')
        #PageTemplate definieren
        myPage = PageTemplate(id='allPages', frames=[f],
            onPage=self.buildHeadFoot, pagesize=(self.breite, self.hoehe))
        self.addPageTemplates(myPage)
        #Inhalt generieren
        widths=(1*cm, 1.25*cm, 2*cm, 1.7*cm, 2.3*cm, 5.5*cm, 2.3*cm, 2.3*cm)
        c_style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
            ('FONTSIZE',(0,0),(-1,-1), 10),
            ]
        data = list()
        for i in text:
            try:
                # String
                self.story.append(Paragraph(i, self.style['BodyText']))
            except AttributeError:
                # List, Tuple
                line = list()
                for o in i:
                    line.append(Paragraph(o, self.style['BodyText']))
                data.append(line)
        t=Table(data, colWidths=widths, style=c_style)
        self.story.append([t])
        return


def main():
    filename = '/home/whtb/Scripte/officeplanet/firmware_officeplanet/reportlab/aaaa.pdf'
    story = [['001', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['002', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['003', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['004', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['005', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['006', '1', 'PALETTE', '100000', '750089123', 'KOPIeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeERPAPIER A4', '700.00', '700.00']]
    with open(filename, 'wb') as f:
        pdf = myPDF(filename)
        pdf.build_story(story)
        pdf.multiBuild(pdf.story)


if __name__ == '__main__':
    main()
Ich erhalte dabei die Fehlermeldung:
Traceback (most recent call last):
File "def_reportlap_table.py", line 155, in <module>
main()
File "def_reportlap_table.py", line 151, in main
pdf.multiBuild(pdf.story)
File "/usr/lib/python2.7/dist-packages/reportlab/platypus/doctemplate.py", line 951, in multiBuild
if thing.isIndexing():
AttributeError: 'list' object has no attribute 'isIndexing'
Komme da leider zu keiner Lösung und könnte Eure Hilfe gebrauchen!

Grüße Nobuddy
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Auch ich hatte reportlab für die Erzeugung von Dokumenten mit Logo und Tabellen genutzt, verwende mittlerweile aber Latex. Dabei werden in Latex-Templates variable Inhalte zunächst substituiert, gespeichert und dann per Subprozess mittels Latex verarbeitet. Das ist recht IO-lastig, geht seit Vorhandensein einer SSD aber sauschnell und sieht super aus - insbesondere Tabellen (besonders mehrseitige). Das muss nicht für jeden Einsatz die richtige Lösung sein, ich möchte sie hier aber dennoch einmal erwähnen.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@kbr, brauche kein Latex, reportlab ist für mein Vorhaben völlig ausreichend. :wink:

Ich habe die Lösung gefunden :)

Code: Alles auswählen

    def build_story(self, text):
        #Frame definieren
        b, h = self.breite, self.hoehe
        f = Frame(1*cm, 2*cm, b - (2 * cm), h - (5.5 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='main')
        #PageTemplate definieren
        myPage = PageTemplate(id='allPages', frames=[f],
            onPage=self.buildHeadFoot, pagesize=(self.breite, self.hoehe))
        self.addPageTemplates(myPage)
        #Inhalt generieren
        widths=(1*cm, 1.25*cm, 2*cm, 1.7*cm, 2.3*cm, 5.5*cm, 2.3*cm, 2.3*cm)
        c_style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
            ('FONTSIZE',(0,0),(-1,-1), 10),
            ]
        data = list()
        for i in text:
            try:
                # String
                self.story.append(Paragraph(i, self.style['BodyText']))
            except AttributeError:
                # List, Tuple
                line = list()
                for o in i:
                    line.append(Paragraph(o, self.style['BodyText']))
                data.append(line)
        if len(data) > 0:
            self.story=[Table(data, colWidths=widths, style=c_style)]
        return
Jetzt wird auch die Tabelle korrekt ausgegeben.

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

statt dem `try... except` könntest du auch `isinstance` in Kombination mit `if` verwenden, also z.B.:

Code: Alles auswählen

for i in text:
    if isinstance(i, str):
        self.story.append(Paragraph(i, self.style['BodyText']))
    elif isinstance(i, list) or isinstance(i, tuple):
        line = list()
        for o in i:
            line.append(Paragraph(o, self.style['BodyText']))
        data.append(line)
    else:
        #z.B. Fehlermeldung in dern Terminal, Log etc.
Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,

Danke für den Tip, jetzt werde ich mich mal an das Tabellen-Projekt ran machen. :wink:

Grüße Nobuddy
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: ist es Absicht, dass 'build_story' bei Übergabe einer Liste von Strings etwas völlig anderes macht als bei Überabe einer Liste von Listen? Werden Listen und Strings gemischt, werden alle Strings ignoriert. Das Verhalten ist sehr überraschend, um nicht zu sagen fehlerhaft.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@Sirius3, bin mir nicht ganz im Klaren, was Du meinst.
Ich erstelle aus einer Liste eine Tabelle, die ich an die Liste 'self.story' nur als Liste übergeben kann.

Hier mein aktueller Stand (Ausgabe ab build_story):

Code: Alles auswählen

    def build_story(self, data):
        #Frame definieren
        b, h = self.breite, self.hoehe
        f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (5.5 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='main')
        #PageTemplate definieren
        myPage = PageTemplate(id='allPages', frames=[f],
            onPage=self.buildHeadFoot, pagesize=(self.breite, self.hoehe))
        self.addPageTemplates(myPage)
        #Inhalt generieren
        try:
            for i in data:
                if isinstance(i, str):
                    self.story.append(Paragraph(i, self.style['BodyText']))
                elif isinstance(i, list) or isinstance(i, tuple):
                    pass
                else:
                    print('Für Type: %s, gibt es keine Workline!' % type(i))
        except TypeError:
           # Tabelle
            self.story.append(data)
        return

    def build_table(self, data, head, widths, style):
        new_list = list()
        new_list.append(head)
        for x in data:
            line = list()
            for text in x:
                line.append(Paragraph(text, self.style['BodyText']))
            new_list.append(line)
        return Table(new_list, colWidths=widths, style=style)


def main():
    filename = '/home/whtb/Scripte/officeplanet/firmware_officeplanet/reportlab/aaaa.pdf'
    story = [['001', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['002', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['003', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['004', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['005', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00']]
    table_head = ['POS', 'ME', 'VE', 'INHALT', 'ARTIKEL',
        'BENENNUNG, # ZEILENINFO', 'EP', 'GP']
    widths=(1.05*cm, 1.25*cm, 2*cm, 1.7*cm, 2.3*cm, 5.5*cm, 2.3*cm, 2.3*cm)
    style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
        ('LINEABOVE',(0,0),(7,0),1,'#BFBFBF'),
        ('LINEABOVE',(0,1),(7,1),1,'#BFBFBF'),
        ('VALIGN',(0,0),(-1,-1),'TOP'),
        ('ALIGN',(0,0),(1,-1),'CENTER'),
        ('ALIGN',(5,0),(5,-1),'CENTER'),
        ('ALIGN',(6,0),(6,-1),'CENTER'),
        ('ALIGN',(1,1),(1,-1),'RIGHT'),
        ('ALIGN',(6,1),(6,-1),'RIGHT'),
        ('ALIGN',(7,1),(7,-1),'RIGHT'),
        ('BACKGROUND',(0,0),(-1,0), '#EAEAEA'),
        ('FONTSIZE',(0,0),(-1,-1), 10),
        ]
    with open(filename, 'wb') as f:
        pdf = myPDF(filename)
        table = pdf.build_table(story, table_head, widths, style)
        pdf.build_story(table)
        pdf.multiBuild(pdf.story)


if __name__ == '__main__':
    main()
Das funktioniert prima, mit einer wie mit mehreren Seiten.
Habe für das Erstellen von Tabellen, 'build_table' erstellt. Dies wird noch weiter ausgebaut werden.

Was mich momentan beschäftigt, ist wie ich den Tabellenkopf auch auf die Folgeseiten bekomme?

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,
hoffe Du kannst mir dabei weiterhelfen.

Mit 'buildHeadFoot(canvas, doc)' und der '@staticmethod', wird für alle Seiten Kopf- und Fußzeile erstellt.
Kann ich mit dieser Methode auch die Zieladresse für den Postversand erstellen, die nur auf der Ersten Seite erscheint?
Wenn ja, wie muß dieses Umgesetzt werden?

Ich habe zwar dieses schon versucht, aber immer nur die erste '@staticmethod' wird ausgegeben und die Weiteren werden ignoriert.
Alternativ habe ich zuerst versucht, die Daten an self.story direkt zu übergeben, was funktioniert hat aber leider mit dem Nebeneffekt, daß das Layout nicht so übernommen wird, wie ich es erstellt habe.

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

bei ReportLab kann ein Dokument aus verschiedenen Templates gebaut werden. D.h. man kann für die 1. Seite ein anderes Template nehmen für Seite 2-X. Und mit diesem Template kann man dann auch andere Methoden für Kopf-/Fußzeile verbinden.

Gemacht habe ich das auch noch nicht, aber ich meine in der ReportLab wäre mindestens ein Beispiel dazu.

Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Inzwischen habe ich für die Absende- und Zieladresse, dies zu '@staticmethod' hinzugefügt:

Code: Alles auswählen

        # Postversand
        if doc.page == 1:
            # Absendeadresse
            canvas.drawString(doc.breite-(19*cm), 24.7 *cm,
                '{}, {}, {}'.format(doc.FIRMA, doc.STREET,
                doc.PLZ + ' ' + doc.ORT))
            # Zieladresse
            canvas.setFont('Helvetica', 11)
            name, name2, street, plz_ort = doc.adresse
            canvas.drawString(doc.breite-(19*cm), 24 *cm, name)
            canvas.drawString(doc.breite-(19*cm), 23.5 *cm, name2)
            canvas.drawString(doc.breite-(19*cm), 22.8 *cm, street)
            canvas.drawString(doc.breite-(19*cm), 22.3 *cm, plz_ort)
        canvas.restoreState()
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

So langsam gefällt mir das mit '@staticmethod', ist wohl die 'Schaltzentrale'.

Bei meinem Projekt, ist die erste Seite anderst als die Folgeseiten, da dort noch die Absendeadresse steht und die Tabelle dadurch tiefer anfängt. Ich zerbreche mir momentan den Kopf, wie ich in der '@staticmethod', den Frame für die erste Seite und die Folgeseiten erstellen kann. So wäre dann immer das richtige Frame für die entsprechende Seite angesprochen.

Code: Alles auswählen

    def build_story(self, data):
        #Frame definieren
        b, h = self.breite, self.hoehe
        # Page 1
        f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (12.2 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='main')
        # Next Pages
        #f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (6.2 * cm),
        #    showBoundary=0, leftPadding=0, rightPadding=0, id='main')
        #PageTemplate definieren
        myPage = PageTemplate(id='allPages', frames=[f],
            onPage=self.buildHeadFoot, pagesize=(self.breite, self.hoehe))
        self.addPageTemplates(myPage)
Da wäre ich für Eure Hilfe und Tips sehr froh!

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

`@staticmethod` ist "nur" ein Dekorator für die Funktion `buildHeadFoot()` das hat mit dem, was ReportLab macht, nicht direkt was zu tun. Und, wie der Name der Funktion schon sagt, wird darin nur Kopf- und Fusszeile gebaut - ob auf der 1. oder 2. oder .... Seite ist der Funktion voll Latte.

Wenn du die erste Seite anders haben willst als Seite 2. bis X, dann geht das anders. Die `build()` Methode des Dokuments kennt `onFirstPage` und `onLaterPages` - damit solltest du das Regeln. Ein einfaches Beispiel findest du im der offziellen Doku im Kapitel 5.2., im Netz findest du mit Sicherheit.
Oder du wechselst selber "von Hand" das Template nach der 1. Seite, siehe z.B. hier: http://code.activestate.com/recipes/123 ... etemplate/

Wie gesagt, praktische Praxiserfahrung habe ich zu dem Thema auch nicht, weil bei meinen PDFs alle Seiten gleich sind.

Gruß, noisefloor
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,
das mit dem Dekorator `@staticmethod` und der Funktion `buildHeadFoot()` habe ich so verstanden.

Auf Deinen Link, bin ich auch zuvor schon gestoßen, momentan ist mir die Umsetzung noch nicht klar.
Die Liste was eingelesen wird, soll ja als Tabelle ausgegeben werden. Nun kann es ja vorkommen, daß in einer Zelle ein sehr langer Text existiert. Dieser wird ja dann umgebrochen und verändert so die Standard-Zeilenhöhe. Aus diesem Grunde kann ich ja auch nicht sagen, "erstelle ab Zeile X eine neue Seite". So ist es ja in dem Link, wenn ich das richtig verstanden habe.

Ich habe folgende Funktionen zusätzlich zu `buildHeadFoot()` erstellt.
# Erstellt zusätzlich für die erste Seite, Briefkopf und Elemente für Rechnungerstellung.
- `buildInvoiceFirst()`
# Erstellt für alle weiteren Seiten, Elemente für Rechnungerstellung.
- `buildInvoiceNext()`

Code: Alles auswählen

class myPDF(BaseDocTemplate):

    def __init__(self, filename, invoice_head, data, adresse, table, **kw):  
        self.allowSplitting = 0  
        BaseDocTemplate.__init__(*(self, filename), **kw)
        self.format = A4
        self.breite, self.hoehe = self.format
        self.author = 'noisefloor'
        self.title = 'ReportLab Document'
        self.subject = 'ReportLab Demo'
        [self.NAME, self.NAME2, self.NAME_ADDITION, self.STREET,
            self.PLZ, self.ORT, self.FIRMA, self.TELEFON, self.FAX,
            self.EMAIL, self.INTERNET, self.BANK, self.BIC, self.IBAN,
            self.UST_IDENT, self.RECHTSFORM] = IDENT
        self.adresse = adresse
        self.table_head, self.widths, self.t_style = table
        self.invoice_head = invoice_head
        self.data = data
        self.encrypt = pdfencrypt.StandardEncryption('',
            ownerPassword='noisefloor',
            canPrint=1,
            canModify=0,
            canCopy=0,
            canAnnotate=1,
            strength=40)
        self.style = getSampleStyleSheet()
        self.story = []

    @staticmethod
    def buildHeadFoot(canvas, doc):
        print('buildHeadFoot', doc.page)
        canvas.saveState()
        canvas.setFillColorRGB(0, 0, 0)
        # Head
        grafik = '{}{}'.format(Path('reportlab'), 'Firmenkopf.png')
        canvas.drawImage(grafik, doc.breite-(7.8*cm), doc.hoehe-(   2.2*cm),
            width=6.8* cm, height=1.7* cm)
        # Foot
        canvas.line(2*cm, 2.25 * cm, doc.breite-(0.5*cm), 2.25 * cm)
        canvas.setStrokeColor('#BFBFBF')
        canvas.setFont('Helvetica', 8.5)
        # Spalte 1 Adresse
        canvas.drawString(doc.breite-(19*cm), 1.75 *cm, doc.FIRMA)
        canvas.drawString(doc.breite-(19*cm), 1.35 *cm, doc.NAME2)
        canvas.drawString(doc.breite-(19*cm), 0.95 *cm, doc.STREET)
        canvas.drawString(doc.breite-(19*cm), 0.55 *cm,
            doc.PLZ + ' ' + doc.ORT)
        # Spalte 2 Komunikation-Definition
        canvas.drawString(doc.breite-(15.05*cm), 1.75 *cm, 'Telefon:')
        canvas.drawString(doc.breite-(15.05*cm), 1.35 *cm, 'Fax:')
        canvas.drawString(doc.breite-(15.05*cm), 0.95 *cm, 'E-Mail:')
        canvas.drawString(doc.breite-(15.05*cm), 0.55 *cm, 'Internet:')
        canvas.drawString(doc.breite-(13.8*cm), 1.75 *cm, doc.TELEFON)
        canvas.drawString(doc.breite-(13.8*cm), 1.35 *cm, doc.FAX)
        canvas.drawString(doc.breite-(13.8*cm), 0.95 *cm, doc.EMAIL)
        canvas.drawString(doc.breite-(13.8*cm), 0.55 *cm, doc.INTERNET)
        # Spalte 3 Bank-Definition
        canvas.drawString(doc.breite-(10.6*cm), 1.75 *cm, doc.BANK)
        canvas.drawString(doc.breite-(10.6*cm), 1.35 *cm, 'BIC:')
        canvas.drawString(doc.breite-(10.6*cm), 0.95 *cm, 'IBAN:')
        canvas.drawString(doc.breite-(9.7*cm), 1.35 *cm, doc.BIC)
        canvas.drawString(doc.breite-(9.7*cm), 0.95 *cm, doc.IBAN)
        # Spalte 5 Definition Inhaber, USt-Ident-Nr
        canvas.drawString(doc.breite-(5*cm), 1.75 *cm, 'Inhaber:')
        canvas.drawString(doc.breite-(5*cm), 1.35 *cm, 'Rechtsform:')
        canvas.drawString(doc.breite-(5*cm), 0.95 *cm, 'USt-Ident-Nr.:')
        canvas.drawString(doc.breite-(3*cm), 1.75 *cm, doc.NAME2)
        canvas.drawString(doc.breite-(3*cm), 1.35 *cm, doc.RECHTSFORM)
        canvas.drawString(doc.breite-(3*cm), 0.95 *cm, doc.UST_IDENT)

        b, h = doc.breite, doc.hoehe
        if doc.page == 1:
            # Absendeadresse
            canvas.drawString(doc.breite-(19*cm), 25.7 *cm,
                '{}, {}, {}'.format(doc.FIRMA, doc.STREET,
                doc.PLZ + ' ' + doc.ORT))
            # Zieladresse
            canvas.setFont('Helvetica', 11)
            name, name2, street, plz_ort = doc.adresse
            canvas.drawString(doc.breite-(19*cm), 25 *cm, name)
            canvas.drawString(doc.breite-(19*cm), 24.5 *cm, name2)
            canvas.drawString(doc.breite-(19*cm), 23.8 *cm, street)
            canvas.drawString(doc.breite-(19*cm), 23.3 *cm, plz_ort)
            f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (12.2 * cm),
                showBoundary=0, leftPadding=0, rightPadding=0, id='firstPage')
            #PageTemplate definieren
            doc.addPageTemplates(PageTemplate(id='firstPage',frames=[f],
                onPage=doc.buildInvoiceFirst(canvas, doc)))
        if doc.page > 1:
            b, h = doc.breite, doc.hoehe
            f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (7.2 * cm),
                showBoundary=0, leftPadding=0, rightPadding=0, id='nextPages')
            #PageTemplate definieren
            doc.addPageTemplates(PageTemplate(id='firstPage',frames=[f],
                onPage=doc.buildInvoiceNext(canvas, doc)))
        canvas.restoreState()

    @staticmethod
    def buildInvoiceFirst(canvas, doc):
        print('buildInvoiceFirst', doc.page)
        canvas.saveState()
        canvas.setFillColorRGB(0, 0, 0)
        # Rechnungkopf
        canvas.setFont('Helvetica', 16)
        canvas.drawString(doc.breite-(19*cm), doc.hoehe-(9.1 *cm), 'RECHNUNG')
        canvas.setFont('Helvetica', 10)
        new_list = doc.invoice_head
        widths=(2.5*cm, 2.5*cm, 2.5*cm, 1.5*cm, 2.3*cm, 2.3*cm)
        t0 = Table(new_list, colWidths=widths, 
            style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
            ('ALIGN',(2,0),(2,-1),'CENTER'),
            ('ALIGN',(3,0),(3,-1),'CENTER'),
            ('BACKGROUND',(0,0),(-1,0), '#EAEAEA'), 
            ('FONTSIZE',(0,0),(-1,-1), 10)
            ])
        t0.wrapOn(canvas, doc.breite, doc.hoehe)
        t0.drawOn(canvas, *doc.coord(6.8, 9.5, cm))
        canvas.setFont('Helvetica', 10)
        # Tabellenkopf
        new_list = [doc.table_head]
        t1 = Table(new_list, colWidths=doc.widths, style=doc.t_style)
        t1.wrapOn(canvas, doc.breite, doc.hoehe)
        t1.drawOn(canvas, *doc.coord(2, 11.05, cm))
        canvas.setFillColorRGB(0, 0, 0)
        #canvas.setStrokeColorRGB(0, 0, 0)
        canvas.setFont('Helvetica', 8)
        text = 'LEISTUNGSZEITPUNKT IST IDENTISCH MIT DEM MONAT DES RECHNUNGDATUMS!'
        canvas.drawString(doc.breite-(14.2*cm), doc.hoehe-(9.9 *cm), text)
        # Tabelle
        #t2 = Table(doc.data, colWidths=doc.widths, style=doc.t_style)
        #t2.wrapOn(canvas, doc.breite, doc.hoehe)
        # t2.drawOn(canvas, *doc.coord(2, 11.05, cm))
        canvas.restoreState()

    @staticmethod
    def buildInvoiceNext(canvas, doc):
        print('buildInvoiceNext', doc.page)
        canvas.saveState()
        canvas.setFillColorRGB(0, 0, 0)
        # Rechnungkopf
        canvas.setFont('Helvetica', 16)
        canvas.drawString(doc.breite-(19*cm), doc.hoehe-(4.1 *cm), 'RECHNUNG')
        canvas.setFont('Helvetica', 10)
        new_list = doc.invoice_head
        widths=(2.5*cm, 2.5*cm, 2.5*cm, 1.5*cm, 2.3*cm, 2.3*cm)
        t0 = Table(new_list, colWidths=widths, 
            style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
            ('ALIGN',(2,0),(2,-1),'CENTER'),
            ('ALIGN',(3,0),(3,-1),'CENTER'),
            ('BACKGROUND',(0,0),(-1,0), '#EAEAEA'), 
            ('FONTSIZE',(0,0),(-1,-1), 10)
            ])
        t0.wrapOn(canvas, doc.breite, doc.hoehe)
        t0.drawOn(canvas, *doc.coord(6.8, 4.5, cm))
        canvas.setFont('Helvetica', 10)
        # Tabellenkopf
        new_list = [doc.table_head]
        t1 = Table(new_list, colWidths=doc.widths, style=doc.t_style)
        t1.wrapOn(canvas, doc.breite, doc.hoehe)
        t1.drawOn(canvas, *doc.coord(2, 6.2, cm))
        canvas.setFont('Helvetica', 8)
        text = 'LEISTUNGSZEITPUNKT IST IDENTISCH MIT DEM MONAT DES RECHNUNGDATUMS!'
        canvas.drawString(doc.breite-(14.2*cm), doc.hoehe-(4.9 *cm), text)
        # Tabelle
        #t2 = Table(doc.data, colWidths=doc.widths, style=doc.t_style)
        #t2.wrapOn(canvas, doc.breite, doc.hoehe)
        #t2.drawOn(canvas, *doc.coord(2, 6.2, cm))
        canvas.restoreState()

    def coord(self, x, y, unit=1):
        x, y = x * unit, self.hoehe - y * unit
        return x, y

    def build_story(self, data):
        #Frame definieren
        b, h = self.breite, self.hoehe
        # Page 1
        f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (12.2 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='firstPage')
        f1 = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (7.2 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='nextPages')
        #PageTemplate definieren
        self.addPageTemplates(PageTemplate(id='firstPage',frames=[f],
            onPage=self.buildHeadFoot))
        #Inhalt generieren
        try:
            for i in data:
                if isinstance(i, str):
                    self.story.append(Paragraph(i, self.style['BodyText']))
                elif isinstance(i, list) or isinstance(i, tuple):
                    pass
                else:
                    print('Für Type: %s, gibt es keine Workline!' % type(i))
        except TypeError:
            # Tabelle
            self.story.append(data)
        return

    def build_table(self):
        new_list = list()
        for x in self.data:
            line = list()
            for text in x:
                line.append(Paragraph(text, self.style['BodyText']))
            new_list.append(line)
        return Table(new_list, colWidths=self.widths, style=self.t_style)


def main():
    filename = '/home/pfad/zu/datei.pdf'
    invoice_head = ['NUMMER', 'DATUM', 'SEITE', 'POS', 'REFERENZ', 'KUNDE']
    invoice_data = ['12345678', '2015.04.09', '1 von 3', '12', 'REFERENZ', 'KUNDE']
    story = [['001', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['002', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['003', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['004', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['005', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['006', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['007', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['008', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['009', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['010', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],]
    table_head = ['POS', 'ME', 'VE', 'INHALT', 'ARTIKEL',
        'BENENNUNG, # ZEILENINFO', 'EP', 'GP']
    widths=(1.05*cm, 1.25*cm, 2*cm, 1.7*cm, 2.3*cm, 5.5*cm, 2.3*cm, 2.3*cm)
    style=[('GRID',(0,0),(-1,-1),0.5,'#BFBFBF'),
        ('LINEABOVE',(0,0),(7,0),1,'#BFBFBF'),
        ('LINEABOVE',(0,1),(7,1),1,'#BFBFBF'),
        ('VALIGN',(0,0),(-1,-1),'TOP'),
        ('ALIGN',(0,0),(1,-1),'CENTER'),
        ('ALIGN',(5,0),(5,-1),'CENTER'),
        ('ALIGN',(6,0),(6,-1),'CENTER'),
        ('ALIGN',(1,1),(1,-1),'RIGHT'),
        ('ALIGN',(6,1),(6,-1),'RIGHT'),
        ('ALIGN',(7,1),(7,-1),'RIGHT'),
        ('BACKGROUND',(0,0),(-1,0), '#EAEAEA'),
        ('FONTSIZE',(0,0),(-1,-1), 10),
        ]
    adresse = ['Müller AG', 'Maschinenteile', 'Teststr. 75', '12345 Piepshausen']
    with open(filename, 'wb') as f:
        pdf = myPDF(filename, [invoice_head, invoice_data], story,
            adresse, (table_head, widths, style))
        table = pdf.build_table()
        pdf.build_story(table)
        pdf.multiBuild(pdf.story)


if __name__ == '__main__':
    main()
Die Erste wie auch die Folgeseiten, werden fehlerfrei erstellt.
Der einzige Fehler, ist daß nach der ersten Seite, die Tabelle an der Position wie bei der ersten Seite anfängt.

Mir fällt dazu momentan keine Lösung ein.
Vielleicht kann jemand von Euch mir den richtigen Schubbser geben?

Grüße Nobuddy
Antworten