Seite 3 von 3

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Samstag 4. April 2015, 13:56
von noisefloor
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Samstag 4. April 2015, 14:45
von Nobuddy
Hallo noisefloor,

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

Grüße Nobuddy

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Samstag 4. April 2015, 15:13
von Sirius3
@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.

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Samstag 4. April 2015, 18:32
von Nobuddy
@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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Dienstag 7. April 2015, 09:12
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Dienstag 7. April 2015, 10:37
von noisefloor
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Dienstag 7. April 2015, 10:48
von Nobuddy
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()

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Dienstag 7. April 2015, 18:46
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Mittwoch 8. April 2015, 11:33
von noisefloor
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Mittwoch 8. April 2015, 13:37
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Mittwoch 8. April 2015, 14:52
von noisefloor
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Mittwoch 8. April 2015, 15:51
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Donnerstag 9. April 2015, 10:16
von Nobuddy
Habe die Lösung :D , poste dies heute Abend!

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Donnerstag 9. April 2015, 17:18
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Donnerstag 9. April 2015, 17:58
von EyDu
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.

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Donnerstag 9. April 2015, 18:25
von Nobuddy
Hallo EyDu,

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

Grüße Nobuddy

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Freitag 10. April 2015, 08:10
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Montag 13. April 2015, 10:21
von Nobuddy
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

Re: Hilfe zum 1 x 1 für reportlab

Verfasst: Montag 20. April 2015, 15:03
von Nobuddy
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