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.
Benutzeravatar
noisefloor
User
Beiträge: 3856
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: 17745
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: 3856
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: 3856
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
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

was IMHO komisch ist, ist, dass du in der Funktion `buildHeadFoot()` die Frames für die Seiten definierst. Eigentlich sollte die Funktion _nur_ die Kopf- und Fußzeile generieren und sonst nichts. Der Rest sollte in eigene Funktionen oder in den Hauptteil des Programms ausgelagert werden.

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

Ja noisefloor, da war die Hoffnung, daß dies eine Lösung wäre, was es aber letztendlich nicht ist. :wink:

Vielleicht hast Du eine Idee, die zur Lösung beitragen könnte?

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

Habe die Lösung :D , poste dies heute Abend!
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Momentan, sieht das dann so aus:

Code: Alles auswählen

class myPDF(BaseDocTemplate):

    def __init__(self, filename, work, **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
        if work['RECHNUNG']:
            invoice, table = work['RECHNUNG']
            (self.adresse, self.invoice_data, self.invoice_head,
                self.invoice_widths, self.invoice_style) = invoice
            (self.data, self.table_head, self.table_widths,
                self.table_style) = table
        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)
            # Erstelle Rechnung, erste Seite
            doc.buildInvoiceFirst(canvas, doc)
        if doc.page > 1:
            # Erstelle Rechnung, zweite und weitere Seiten
            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)
        doc.invoice_data[2] = '{} von {}'.format(doc.page, '3')
        t0 = Table([doc.invoice_head, doc.invoice_data],
            colWidths=doc.invoice_widths, style=doc.invoice_style)
        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.table_widths,
            style=doc.table_style)
        t1.wrapOn(canvas, doc.breite, doc.hoehe)
        t1.drawOn(canvas, *doc.coord(2, 11.05, cm))
        canvas.setFillColorRGB(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)
        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)
        doc.invoice_data[2] = '{} von {}'.format(doc.page, '3')
        t0 = Table([doc.invoice_head, doc.invoice_data],
            colWidths=doc.invoice_widths, style=doc.invoice_style)
        t0.wrapOn(canvas, doc.breite, doc.hoehe)
        t0.drawOn(canvas, *doc.coord(6.8, 4.5, cm))
        canvas.setFont('Helvetica', 10)
        # Tabellenkopf
        t1 = Table([doc.table_head], colWidths=doc.table_widths,
            style=doc.table_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)
        canvas.restoreState()

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

    def build_story(self):
        #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),
            PageTemplate(id='nextPages',frames=f1, onPage=self.buildHeadFoot)
            ])
        self.story.append(NextPageTemplate('nextPages'))
        #Inhalt generieren
        for i in self.data:
            print(i)
            if isinstance(i, str):
                self.story.append(Paragraph(i, self.style['BodyText']))
            elif isinstance(i, list) or isinstance(i, tuple):
                for text in i:
                    self.story.append(Paragraph(text, self.style['BodyText']))
            else:
                print('Für Type: %s, gibt es keine Workline!' % type(i))
        return

    def build_table(self):
        #Frame definieren
        b, h = self.breite, self.hoehe
        # Page 1
        f = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (12.8 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='firstPage')
        f1 = Frame(1.7*cm, 2*cm, b - (2 * cm), h - (8 * cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='nextPages')
        #PageTemplate definieren
        self.addPageTemplates([
            PageTemplate(id='firstPage',frames=f, onPage=self.buildHeadFoot),
            PageTemplate(id='nextPages',frames=f1, onPage=self.buildHeadFoot)
            ])
        self.story.append(NextPageTemplate('nextPages'))
        new_list = list()
        for i, x in enumerate(self.data):
            line = list()
            for text in x:
                line.append(Paragraph(text, self.style['BodyText']))
            new_list.append(line)
            if i == 20:
                self.story.append(Table(new_list, colWidths=self.table_widths,
                    style=self.table_style))
                new_list = list()
        self.story.append(Table(new_list, colWidths=self.table_widths,
            style=self.table_style))
        return


def main():
    filename = '/home/pfad/zu/mein.pdf'
    invoice_head = ['NUMMER', 'DATUM', 'SEITE', 'POS', 'REFERENZ', 'KUNDE']
    invoice_data = ['12345678', '2015.04.09', '1 von 3', '12', 'REFERENZ', 'KUNDE']
    invoice_widths=(2.5*cm, 2.5*cm, 2.5*cm, 1.5*cm, 2.3*cm, 2.3*cm)
    invoice_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)]
    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'],
        ['011', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['012', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['013', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['014', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['015', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['016', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['017', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['018', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['019', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['020', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['021', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['022', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['023', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['024', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['025', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['026', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['027', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['028', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['029', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['030', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['031', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['032', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['033', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['034', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['035', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['036', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['037', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['038', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['039', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['040', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['041', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['042', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['043', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['044', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['045', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['046', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['047', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['048', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['049', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['050', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['051', '50', 'STÜCK', '100000', 'TEST', '12345678901234567890123456789012345678901234567890 TEST ENTHÄLT TEXT', '0.75', '37.50'],
        ['052', '5000', 'STÜCK', '100000', '4711ABC', 'KARTOFFELCHIPS', '0.75', '3.75'],
        ['053', '50', 'STÜCK', '100000', '9999ABC', 'BLEISTIFT HB', '0.25', '12.50'],
        ['054', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],
        ['055', '1', 'PALETTE', '100000', '750089123', 'KOPIERPAPIER A4', '700.00', '700.00'],]
    table_head = ['POS', 'ME', 'VE', 'INHALT', 'ARTIKEL',
        'BENENNUNG, # ZEILENINFO', 'EP', 'GP']
    table_widths=(1.05*cm, 1.25*cm, 2*cm, 1.7*cm, 2.3*cm, 5.5*cm, 2.3*cm, 2.3*cm)
    table_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']
    work = {'RECHNUNG' : [[adresse, invoice_data, invoice_head, 
        invoice_widths, invoice_style], [story, table_head, table_widths,
        table_style]]}
    with open(filename, 'wb') as f:
        pdf = myPDF(filename, work)
        pdf.build_table()
        #pdf.build_story()
        pdf.multiBuild(pdf.story)


if __name__ == '__main__':
    main()
Seite 1 kann ein anderes Layout, als die Folgeseiten besitzen.
Die Tabelle passt sich nun den Seiten entsprechend an.

Die Funktion 'build_story' muß ich noch anpassen, funktioniert momentan nicht!

Was noch fehlt, ist die Aktualisierung der Seitenangaben (Page of AllPages).
Vielleicht habt Ihr mir da eine einfache Lösung?

Tips und Verbesserungen, gerne jeder Zeit.

Grüße Nobuddy
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du solltest schleunigst deinen Code zusammenfassen. Zeilen 45 bis 71 unterscheiden sich nur minimal, und buildInvoiceFirst und buildInvoiceNext sind fast identisch. Im ganzen Code sind dann noch andere Stellen, häufig in zwei oder mehr folgenden Zeilen, die gleich sind. Wenn du jetzt nicht aufräumst, dann steigst du bald nicht mehr durch. Und helfen will dir dann auch keiner mehr.

An den Namen solltest du auch arbeiten: b, h, f, f1, new_list, t0, t1 sind alle nichtssagend. Als Faustregel gilt: Wenn dir kein vernünftiger Name einfällt, dann stimmt etwas an deinem Code nicht. Und wenn du lange Bezeichner mit einem Buchstaben abkürzt, dann sind die Namen schlecht oder eine Funktion macht zu viel und sollte geteilt werden.
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo EyDu,

Danke für Deinen Input, werde diese Dinge ändern. :wink:

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

Hier mal meine aktuelle Änderungen:

Code: Alles auswählen

class myPDF(BaseDocTemplate):
    """
    Erstellung im PDF-Format von:
    ANGEBOT, AUFTRAGBESTÄTIGUNG, GUTSCHRIFT, LIEFERSCHEIN, RECHNUNG
    """

    def __init__(self, filename, work, **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
        for document in ['ANGEBOT', 'AUFTRAGBESTÄTIGUNG', 'GUTSCHRIFT',
                'LIEFERSCHEIN', 'RECHNUNG']:
            try:
                invoice, table = work[document]
                (self.adresse, self.invoice_data, self.invoice_head,
                    self.invoice_widths, self.invoice_style) = invoice
                (self.data, self.table_head, self.table_widths,
                    self.table_style) = table
                self.document = document
                break
            except KeyError:
                pass
        try:
            self.document
        except AttributeError:
            print('%s, ist kein Dokument dieser Class!' %
                ''.join(work.keys()))
            return None, exit()
        self.text = TEXT
        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):
        """
        Erstelle Kopf- und Fußzeile von Dokument.
        """

        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
        breite = doc.breite-(19*cm)
        canvas.drawString(breite, 1.75*cm, doc.FIRMA)
        canvas.drawString(breite, 1.35*cm, doc.NAME2)
        canvas.drawString(breite, 0.95*cm, doc.STREET)
        canvas.drawString(breite, 0.55*cm, doc.PLZ + ' ' + doc.ORT)
        # Spalte 2 Komunikation-Definition
        breite = doc.breite-(15.05*cm)
        canvas.drawString(breite, 1.75*cm, 'Telefon:')
        canvas.drawString(breite, 1.35*cm, 'Fax:')
        canvas.drawString(breite, 0.95*cm, 'E-Mail:')
        canvas.drawString(breite, 0.55*cm, 'Internet:')
        breite = doc.breite-(13.8*cm)
        canvas.drawString(breite, 1.75*cm, doc.TELEFON)
        canvas.drawString(breite, 1.35*cm, doc.FAX)
        canvas.drawString(breite, 0.95*cm, doc.EMAIL)
        canvas.drawString(breite, 0.55*cm, doc.INTERNET)
        # Spalte 3 Bank-Definition
        breite = doc.breite-(10.6*cm)
        canvas.drawString(breite, 1.75*cm, doc.BANK)
        canvas.drawString(breite, 1.35*cm, 'BIC:')
        canvas.drawString(breite, 0.95*cm, 'IBAN:')
        breite = doc.breite-(9.7*cm)
        canvas.drawString(breite, 1.35*cm, doc.BIC)
        canvas.drawString(breite, 0.95*cm, doc.IBAN)
        # Spalte 5 Definition Inhaber, USt-Ident-Nr
        breite = doc.breite-(5*cm)
        canvas.drawString(breite, 1.75*cm, 'Inhaber:')
        canvas.drawString(breite, 1.35*cm, 'Rechtsform:')
        canvas.drawString(breite, 0.95*cm, 'USt-Ident-Nr.:')
        breite = doc.breite-(3*cm)
        canvas.drawString(breite, 1.75*cm, doc.NAME2)
        canvas.drawString(breite, 1.35*cm, doc.RECHTSFORM)
        canvas.drawString(breite, 0.95*cm, doc.UST_IDENT)
        if doc.page == 1:
            doc.buildPostAdress(canvas, doc)
        doc.buildDocument(canvas, doc)
        canvas.restoreState()


    @staticmethod
    def buildPostAdress(canvas, doc):
        """
        Erstelle Absende- und Ziel-Adresse im Bereich des Brieffenster.
        """

        canvas.saveState()
        canvas.setFillColorRGB(0, 0, 0)
        breite = doc.breite-(19*cm)
        # Absendeadresse im Brief-Fenster
        canvas.drawString(breite, 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(breite, 25*cm, name)
        canvas.drawString(breite, 24.5*cm, name2)
        canvas.drawString(breite, 23.8*cm, street)
        canvas.drawString(breite, 23.3*cm, plz_ort)
        canvas.restoreState()


    @staticmethod
    def buildDocument(canvas, doc):
        """
        Erstelle Basislayout für Dokument
        """

        print('buildInvoice', doc.page)
        canvas.saveState()
        canvas.setFillColorRGB(0, 0, 0)
        # Rechnungkopf, Dokumentenart
        canvas.setFont('Helvetica', 16)
        breite = doc.breite-(19*cm)
        if doc.document == 'AUFTRAGBESTÄTIGUNG':
            x, y = breite, doc.hoehe-(8.7*cm)
            if doc.page > 1:
                x, y = breite, doc.hoehe-(3.7*cm)
            canvas.drawString(x, y, 'AUFTRAG-')
            x, y = breite, doc.hoehe-(9.4*cm)
            if doc.page > 1:
                x, y = breite, doc.hoehe-(4.4*cm)
            canvas.drawString(x, y, 'BESTÄTIGUNG')
        else:
            x, y = breite, doc.hoehe-(9.1*cm)
            if doc.page > 1:
                x, y = breite, doc.hoehe-(4.1*cm)
            canvas.drawString(x, y, doc.document)
        # Rechnungkopf, Rechnungsdaten
        canvas.setFont('Helvetica', 10)
        x, y = 6.8, 9.5
        if doc.page > 1:
            x, y = 6.8, 4.5
        doc.invoice_data[2] = '{} von {}'.format(doc.page, '3')
        doc.TableWrapDraw(canvas, doc, doc.breite, doc.hoehe, x, y,
            Table([doc.invoice_head, doc.invoice_data],
            colWidths=doc.invoice_widths, style=doc.invoice_style))
        # Zusatztext zu Rechnungkopf
        canvas.setFont('Helvetica', 8)
        breite = doc.breite-(14.2*cm)
        x, y = breite, doc.hoehe-(9.9*cm)
        if doc.page > 1:
            x, y = breite, doc.hoehe-(4.9*cm)
        if doc.document.startswith(('GUTSCHRIFT', 'LIEFERSCHEIN',
                'RECHNUNG')):
            canvas.drawString(x, y, doc.text)
        # Tabellenkopf
        canvas.setFont('Helvetica', 10)
        x, y = 2, 11.05
        if doc.page > 1:
            x, y = 2, 6.05
        doc.TableWrapDraw(canvas, doc, doc.breite, doc.hoehe, x, y,
            Table([doc.table_head], colWidths=doc.table_widths,
            style=doc.table_style))
        canvas.restoreState()


    def TableWrapDraw(self, canvas, doc, breite, hoehe, x, y, table):
        """
        Erstelle Tabelle für Funktion buildDocument.
        """

        table.wrapOn(canvas, breite, hoehe)
        table.drawOn(canvas, *doc.coord(x, y, cm))
        return


    def coord(self, x, y, unit=1):
        """
        Ausgabe der x- und y-Koordinaten für Funktion TableWrapDraw.
        """

        x, y = x * unit, self.hoehe - y * unit
        return x, y


    def build_table(self):
        """
        Erstelle Tabellen-Layout für Dokument.
        """

        #Frame definieren
        f = Frame(1.7*cm, 2*cm, self.breite-(2*cm), self.hoehe-(12.8*cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='firstPage')
        f1 = Frame(1.7*cm, 2*cm, self.breite-(2*cm), self.hoehe-(7.8*cm),
            showBoundary=0, leftPadding=0, rightPadding=0, id='nextPages')
        #PageTemplate definieren
        self.addPageTemplates([
            PageTemplate(id='firstPage',frames=f, onPage=self.buildHeadFoot),
            PageTemplate(id='nextPages',frames=f1, onPage=self.buildHeadFoot)
            ])
        self.story.append(NextPageTemplate('nextPages'))
        for i, x in enumerate(self.data):
            line = list()
            for text in x:
                line.append(Paragraph(text, self.style['BodyText']))
            self.story.append(Table([line], colWidths=self.table_widths,
                style=self.table_style))
        return
Es fehlen noch ein paar spezifische Dinge, die ich nach und nach einpflegen werde.
Eine Lösung für das Problem der Ausgabe für 'Page of allPages', fehlt noch.

Weitere Tips und Anregungen, im gerne. :wink:

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

Zum Zusammenführen von Zellen (SPAN), habe ich folgende Funktion geschrieben:

Code: Alles auswählen

    def table_span(self, x, y):
        """
        Zellen-Zusammenführung aus mehreren Spalten zu einer Zelle.

        self.start_x, self.end_x = 0, 5
        self.start_y, self.end_y = 0, 1

              START_RESULT
              #################################################################
        col_0 # row_0 # row_1 # row_2 # row_3 # row_4 # row_5 # row_6 # row_7 #
              #################################################################
        col_1 # row_0 # row_1 # row_2 # row_3 # row_4 # row_5 # row_6 # row_7 #
              #################################################################

              END_RESULT
              #################################################################
        col_0 #                                               # row_6 # row_7 #
              # --------------------- row_0 ------------------#################
        col_1 #                                               # row_6 # row_7 #
              #################################################################
        """

        # Definition von span
        start_x, end_x = x
        start_y, end_y = y
        # Anzahl Spalten und zeilen
        columns = len(self.table_head)
        span_style = self.table_style
        for i in self.y_begin2span:
            i_0 = i + end_y
            i_1 = i
            for x in range(start_x, end_x + 1):
                span_style.append(('SPAN',(x, i_0),(x, i_1)))
        return span_style
Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Als Lösung für 'Page of Pages', lasse ich einmal den Code durchlaufen und ermittle so die Anzahl der Seiten.
Beim zweiten Durchlauf, übergebe ich dann diese Seiten-Info.
Das ist zwar nicht das Ultimative, aber zumindest funktioniert es.

Ich suche noch eine Lösung, für die Y-Postion einer Zelle innerhalb der Tabelle.
Leider habe ich beim Googeln nichts gefunden, was nicht heißen soll dass es dies nicht geben könnte.
Gibt es dafür eine Lösung und wenn ja, wie sieht diese aus?

Grüße Nobuddy
Antworten