Wir wollen viel und variabel drucken!

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Antworten
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hallo!

Ich habe eine Datenbank mit vielen Adressen. Nun möchte ich alle schön auf Etiketten drucken. Diese Etiketten kleben genügsam auf einem A4-Blatt, in meinem Beispiel 3x7 Etiketten pro Blatt.

Die Anzahl der Datensätze ist natürlich von Druck zu Druck unterschiedliche. Auch die Anzahl und Anordnung der Etiketten pro Blatt kann sich ändern. Das wird aber vor dem Druck abgefragt und ist pro Druck bekannt.

Am einfachsten wäre es, denke ich, eine große HTML-Tabelle zu erstellen, füllen und an den Drucker zu senden.
Aber wer parst mir dann das HTML?
Als Alternative dachte ich, dass man es als Datei speichern um es dann automatisch mit dem Browser aufrufen zu lassen. Evtl ein JavaScript-Schnippsel zum Start des Druckdialogs.
Dann sollte es mit Hilfe von CSS doch auch möglich sein, dass die Felder der Tabelle pro Seite denen der Vorgabe entsprechen, oder?
Aber eigentlich ist das nicht mein Wunsch.

Das Programm soll möglichst einfach sein. Am besten der Nutzer bekommt garkeine Datensätze zu sehen sondern nur den Druckdialog.
Auch wäre es wünschenswert, alles mit GTK-Boardmitteln(Gnome) zu erledigen.


http://de.wikibooks.org/wiki/Python-Pro ... _mit_PyGTK
Wie steht ihr dazu? Was lässt sich damit machen?

Kennt und nutzt ihr Alternativen? Habt ihr ander Lösungsvorschläge?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Erinnert mich daran, wie ich mal Namensschilder mithilfe der PIL gedruckt habe: http://www.python-forum.de/topic-11450.html
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hi!
Danke, das ist auf jeden Fall mal ein Anfang und könnte eine Grundlage für weiteres Bilden!

Wie hast du das mit dem Druck im Endeffekt gelöst? Hast du die generierten Bilder dann einzeln geöffnet und gedruckt?
Bei drei oder vier Blättern halte ich das für machbar, aber ich hab mindestens 1000 Datensätze zu verarbeiten...

Gibt es noch weitere Ideen?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
lunar

Müsste ich das Drucken selbst implementieren, würde ich den gezeigten PIL-Code auf Qt portieren. Dort kann man quasi direkt auf den Drucker zeichnen, um die eigentliche Ansteuerung des Druckers kümmert sich Qt. Mit anderen Toolkits mag das auch funktionieren, aber ich kenne nur Qt.

Wenn dagegen externe Programme zur Verfügung stehen, würde ich das nicht selbst tun. Unter Unix-Systemen reicht ein Shell-Einzeiler, um beliebig viele PNG-Dateien mittels ImageMagick in eine PDF-Dateien zu konvertieren und über lpr an das Drucksystem zu übergeben. Unter Windows könnte man zum Druck vieler Bilder beispielsweise IrfanView verwenden, dieses Programm hat, wenn ich mich recht erinnere, ziemlich umfangreiche Unterstützung für den automatisierten Druck vieler Bilder.
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hallo!

Mit QT möchte ich nicht anfangen da mein Interface nun auf GTK aufbaut.

Auf meiner Suche bin ich auf reportlab gestoßen. Wunderbar! Schon die erste Seite des UserGuide hat mich überzeugt, dass ich mein "Ausdruck" darüber laufen lassen werde. Ein PDF erstellen und zu füllen ist damit ja wirklich wahnsinnig einfach. Mit dem PDF kann man dann ja auch wieder andere Sachen anstellen :)

Nun muss ich das ganze zum Drucker schicken.
Am liebsten wäre mir dabei, wenn man dazu gtk.PrintOperation() nutzen könnte. Soll heißen: Der Nutzer druckt auf einen Button "Drucken", das PDF wird erstellt und der Druck-Dialog öffnet sich. Nun könnte man weitere Druckeinstellungen tätigen. Der Druckvorgang wird dann ja, wenn ich es recht verstehe, vom OS übernommen.

Leider habe ich auf meiner Suche bis jetzt nicht gefunden, oder nicht verstanden und so überlesen :( , wie ich eine PDF-Datei an genau diesen Dialog schicke.

Das drucken ginge sicher auch ganz einfach über "lp datei.pdf", doch ich will den Druckdialog :)

Wonach müsste ich suchen? Oder hat jemand direkt einen Tipp für mich?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hello again!

Ich habe mich nun mit reportlab auseinandergesetzt und folgendes zusammengeschustert:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import *
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
import sqlite3

def exportToPdf(getdata, col=3, row=7):
    """ Daten aus Liste 'data' werden nach 'col' und 'row' umgepackt und
        in eine Tabelle geschrieben."""

    part = []
    data = []
    # 'getdate' wird umgewandelt um 'col' und 'row' zu entsprechen
    for i in getdata :
        if len(part) < col :
            part.append(i)
        else :
            data.append(part)
            part = []
            part.append(i)

    # festlegen der Optionen für PDF und Tabelle
    elements = []
    styles = getSampleStyleSheet()
    doc = SimpleDocTemplate('export.pdf',
            pagesize=A4,
            topMargin=10,
            bottomMargin=10,
            title='Adressen-Export',
            author='reportlab')
    options= [
            ('ALIGN', (1,1), (1,1), 'LEFT'),
            #~ ('GRID', (0,0), (-1,-1), 0.0,colors.black),
            ('LEFTPADDING', (0,0), (-1,-1), 25),
            ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
            ]
    width, height = A4

    # erstellen der Tabelle (Anpassung an oberen und unteren Rand der Seite)
    table = Table(data, colWidths=(width/col)-1,
                rowHeights=((height-45)/row), style=options)
    elements.append(table)
    doc.build(elements)


def getExportData(template="VORNAME NAME\nSTRASSE\nPLZZ ORT"):
    """ Einfache Ausgabe der Datensätze in das Format 'template'."""

    connection = sqlite3.connect('db.db')
    cursor = sqlite3.Cursor(connection)
    query =  """SELECT VORNAME, NAME, STRASSE, LAND, PLZZ, ORT
            FROM 'Kontakte' ORDER BY PLZZ ASC"""
    cursor.execute(query)
    alldata = cursor.fetchall()
    data = []
    for i in alldata :
        strs=template
        strs=strs.replace("VORNAME",i[0])
        strs=strs.replace("NAME", i[1])
        strs=strs.replace("STRASSE", i[2])
        strs=strs.replace("LAND", i[3])
        strs=strs.replace("PLZZ", i[4])
        strs=strs.replace("ORT", i[5])
        data.append(strs)
    return data
    connection.commit()

exportToPdf(getExportData(), 3, 7)
Meinungen und Verbesserungen dazu?
Vorallem zu Zeile 17-25, gibt es da nicht eine bessere Lösung?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo,

hier ein paar Vorschläge:

- PEP 8 (hier bezüglich Funktionsnamen) lesen
- Zeile 17 bis 24: Such mal nach Slicing, damit geht es relativ einfach
- Allgemeiner Tipp: Man kann Listen auch gleich mit Inhalt erstellen. Aus Zeilen 23 und 24 wird damit: part =
- Was soll das "elements" in Zeile 27? In Zeile 47 reicht auch ein: doc.build([table])
- Zeilen 60 bis 68 kann man in zwei verschachtelten for-Schleifen lösen. Du iterierst dabei einfach über die Liste ["VORNAME", "NAME", ...] und schaust dir noch die "zip"-Funktion an.
- Wenn du den vorherigen Tipp befolgt hast, dann wirfst du auch noch einen Blick auf List Comprehensions
- Zeile 70 wird niemals erreicht, da vorher immer das "return" ausgeführt wird.
- Benutze richtige Namen. "strs" und "data" sagen genau nichts aus.
Das Leben ist wie ein Tennisball.
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

So, nun hab ich es überarbeitet:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import *
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
import sqlite3

def export_pdf(getdata, col=3, row=7):
    """ Daten aus Liste 'data' werden nach 'col' und 'row' umgepackt und
        in eine Tabelle geschrieben."""

    # Aus 10 Zeilen mach 3!
    exportdata = []
    [exportdata.append(getdata[x*col:x*col+col]) for x in
            range(len(getdata)) if not len(getdata[x*col:x*col+col]) == 0]

    # festlegen der Optionen für PDF und Tabelle
    styles = getSampleStyleSheet()
    doc = SimpleDocTemplate('export.pdf',
            pagesize=A4,
            topMargin=10,
            bottomMargin=10,
            title='Adressen-Export',
            author='python')
    options= [
            ('ALIGN', (1,1), (1,1), 'LEFT'),
            #~ ('GRID', (0,0), (-1,-1), 0.0,colors.black),
            ('LEFTPADDING', (0,0), (-1,-1), 25),
            ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
            ]
    width, height = A4
    # erstellen der Tabelle (Anpassung an oberen und unteren Rand der Seite)
    table = Table(exportdata, colWidths=(width/col)-1,
                rowHeights=((height-45)/row), style=options)
    doc.build([table])


def get_data(template="VORNAME NAME\nSTRASSE\nPLZZ ORT"):
    """ Einfache Ausgabe der Datensätze in das Format 'template'."""

    connection = sqlite3.connect('../Datenbank/db.db')
    cursor = sqlite3.Cursor(connection)
    querydata = ["VORNAME", "NAME", "STRASSE", "LAND", "PLZZ", "ORT"]
    placeholder = ",".join('?' * len(querydata))
    query =  "SELECT %s FROM 'Kontakte' ORDER BY PLZZ ASC" % (placeholder)
    cursor.execute(query, querydata)
    alldata = cursor.fetchall()
    #~ print alldata
    exportdata = []
    for i in alldata :
        templatestring=template
        for x in range(len(querydata)) :
            templatestring=templatestring.replace(querydata[x], i[x])
        exportdata.append(templatestring)
    connection.commit()
    return exportdata

export_pdf(get_data(), 3, 7)

Doch nun hab ich bei der SQL-Abfrage ein Problem, er gibt mir nur folgendes aus (Zeile 50):

Code: Alles auswählen

[(u'VORNAME', u'NAME', u'STRASSE', u'LAND', u'PLZZ', u'ORT'), (u'VORNAME', u'NAME', u'STRASSE', u'LAND', u'PLZZ', u'ORT'...
Er sollte mir hier aber doch die Daten ausgeben. Wo ist der Fehler? Ich häng wohl schon zu lange darüber...
EyDu hat geschrieben: - Zeilen 60 bis 68 kann man in zwei verschachtelten for-Schleifen lösen. Du iterierst dabei einfach über die Liste ["VORNAME", "NAME", ...] und schaust dir noch die "zip"-Funktion an.
Wie man dabei das zip verwenden soll ist mir leider nicht aufgegangen...

Sonst alles gut mit dem Code?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Eine Lösung hab ich bis jetzt nicht gefunden.

Sollte:

Code: Alles auswählen

    querydata = ['VORNAME', 'NAME', 'STRASSE', 'LAND', 'PLZZ', 'ORT']
    placeholder = ",".join('?' * len(querydata))
    query =  "SELECT %s FROM 'Adressdaten' ORDER BY PLZZ ASC" % (placeholder)
    cursor.execute(query, querydata)
nicht eigentlich das gleiche sein wie

Code: Alles auswählen

    cursor.execute("SELECT VORNAME, NAME, STRASSE, LAND, PLZZ, ORT FROM 'Adressdaten' ORDER BY PLZZ ASC")
Frei nach qmark: [wiki]Parametrisierte SQL-Queries[/wiki]
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nein, das ist nicht da selbe. Bei execute können nur WERTE übergeben werden, keine Schlüssel.

Die zusammengesetzte Anfrage ergibt:

Code: Alles auswählen

cursor.execute("SELECT 'VORNAME', 'NAME', 'STRASSE', 'LAND', 'PLZZ', 'ORT' FROM 'Adressdaten' ORDER BY PLZZ ASC")
Das Leben ist wie ein Tennisball.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Soweit ich weiß können Spaltennamen nicht über Platzhalter eingefügt werden sondern nur Werte...
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Aha! Danke dir, das wusste ich nicht.
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Antworten