Grafik drucken

Plattformunabhängige GUIs mit wxWidgets.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Grafik drucken

Beitragvon Mawilo » Freitag 14. Dezember 2007, 07:39

Hallo,

mittlerweile komme ich ganz gut mit dem Darstellen von Grafiken zurecht. Was noch fehlt, ist das Drucken. Da komme ich nicht so richtig weiter.

Ich habe folgendes kleines Programm zum Testen:

Code ausgelagert: http://paste.pocoo.org/show/15836/

Wie kann ich das ausdrucken, so dass der Header auf jeder Seite gedruckt wird (unter Linux und Windows)? Ein kleines Code-Beispiel zum Verstehen wäre nicht schlecht :wink:
Bisher verweigert der Drucker jegliche Mitarbeit, was aber auf das zwischen dem Stuhl und der Tastatur befindliche Problem zurückzuführen ist. :oops:

Mawilo

Edit by Gerold: Code ausgelagert
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Re: Grafik drucken

Beitragvon gerold » Freitag 14. Dezember 2007, 08:09

Mawilo hat geschrieben:Was noch fehlt, ist das Drucken. Da komme ich nicht so richtig weiter.

Hallo Mawilo!

Drucken ist etwas schwieriger. Statt dass du auf den Bildschirm zeichnest, zeichnest du in ein wx.Printout-Objekt.
Ich habe selber noch nichts mit wxPython gedruckt. Deshalb kann ich dich auch nur auf das Kapitel 17 (Seiten 504-520) in "wxPython in Action" hinweisen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Freitag 14. Dezember 2007, 08:33

Hallo Gerold,

damit habe ich schon etwas probiert - aber mehr nach dem Prinzip "Versuch und Irrtum". Mir fehlt da noch etwas das Verständnis, da dort auch nur Text gedruckt wird.

Kann man einfacher eine pdf-Datei erzeugen?

Mawilo
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Freitag 14. Dezember 2007, 09:21

Mawilo hat geschrieben:Kann man einfacher eine pdf-Datei erzeugen?

Hallo Mawilo!

Eine PDF-Datei erstellst du, indem du auf einen PDF-Drucker ausdrucken lässt. ;-) -- Kein Schmäh. Unter Windows verwende ich dafür den PDFCreator http://de.wikipedia.org/wiki/PDFCreator und unter Linux ist sowiso meist ein PDF-Drucker unter Cups eingerichtet.

Ich habe das jetzt mal versucht. Dieser Code stellt das Minimum dar, das man braucht um mit wxPython drucken zu können:

Code: http://paste.pocoo.org/show/15560/

Ich sagte doch, dass es nicht einfach ist. :roll:

mfg
Gerold
:-)

EDIT: Code ausgelagert
Zuletzt geändert von gerold am Freitag 14. Dezember 2007, 10:51, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Freitag 14. Dezember 2007, 10:24

Hallo Gerold,

vielen Dank für die Hilfe. Mir gehen die Fragen aber noch nicht aus ... :D

In dem Beispiel wird die Ausgabe erst mit der Druckvorschau erstellt. Ich habe aber die gewünschte Grafik schon vorher erstellt. Kann ich diese an die Druckklasse übergeben oder muss ich das ganze noch einmal erstellen lassen? Ich müsste also den device context irgendwie weiterreichen?

[Edit] Code weiter unter [/Edit]
Zuletzt geändert von Mawilo am Freitag 14. Dezember 2007, 13:52, insgesamt 1-mal geändert.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Freitag 14. Dezember 2007, 10:50

Mawilo hat geschrieben:Ich habe aber die gewünschte Grafik schon vorher erstellt. Kann ich diese an die Druckklasse übergeben oder muss ich das ganze noch einmal erstellen lassen? Ich müsste also den device context irgendwie weiterreichen?

Hallo Mawilo!

Ich habe mir jetzt deinen Code nicht angesehen. Aber hier die Möglichkeiten:

Wenn etwas auf dem Bildschirm **sichtbar** ist, dann kannst du von diesem Bereich mit ``wx.DC.Blit()`` den sichtbaren Bereich vom DC kopieren. Das ist aber nicht zuverlässig und bei Fenstern mit Scrollbars nicht zielführend.

Die andere Variante ist die, dass du immer zuerst alles in ein Bitmap zeichnest. Dieses Bitmap lässt du dann mit ``wx.BufferedPaintDC()`` im Paint-Eventhandler auf den Bildschirm zeichnen und du kannst dieses Bitmap auch zum Drucken auslesen. -- Einfach das Bitmap an einen ``wx.MemoryDC()`` hängen und mit ``wx.DC.Blit()`` vom MemoryDC in den DC des ``wx.Printout``-Objekts kopieren.

EDIT BEGIN
Mit ``wx.DC.DrawBitmap`` sparst du dir das Anhängen des Bitmaps an den MemoryDC.
EDIT END

Damit wird aber jede jede Seite als Bitmap **zusätzlich** im Speicher gehalten. Das könnte bei vielen Seiten am Speicher zehren. Also entweder du lagerst die Bitmaps auf die Festplatte aus oder du merkst dir, wie die Seiten erzeugt wurden und erzeugst diese zum Drucken noch einmal neu. Das ist der Idealfall.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Freitag 14. Dezember 2007, 13:50

Hallo Gerold,

dank Deiner Hilfe kann ich jetzt etwas drucken. Ich rufe mit dem neuen device context die "alte" Funktion wieder auf. Nach einem Rechtsklick öffnet sich die Druckvorschau.
Jetzt muss das ganze nur noch auf mehrere Seiten verteilt werden. :cry:

Code ausgelagert: http://paste.pocoo.org/show/15835/

Mawilo


Edit by Gerold: Code ausgelagert
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Freitag 14. Dezember 2007, 15:06

Hallo Mawilo!

Jetzt bist du an dem Punkt angelangt, an dem es so richtig schwierig wird. :roll:

Du musst selbst herausfinden, wie viel Platz du für deine Details brauchst. Und bei der Druckvorbereitung (OnPreparePrinting) musst du deine Details einer Seite zuordnen. Also musst du bei dieser Vorbereitung alle Details durchgehen. Herausfinden, wie viel Platz diese brauchen und auf die Seiten aufteilen.

Dann speicherst du die Seitenanzahl. wxPython ruft dann für jede Seite die Methode OnPrintPage auf. In dieser schnappst du dir dann die der übergebenen Seite zugeordneten Details und generierst daraus die Seite.

----

Je komplexer ein Programm wird, desto mehr arbeite ich mit Klassen. In so einem Fall wie hier, würde ich sogar für den Header, für den Footer und für die einzelnen Details je eine Klasse verwenden. So kann ich für jedes Objekt die Größe berechnen, noch bevor gezeichnet wird. Diese Objektgröße kann ich dann zum Anordnen (auf dem DC) und zum Aufteilen der Seiten verwenden.

Z.B. so (Pseudocode):

Code ausgelagert: http://paste.pocoo.org/show/15582/

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Samstag 15. Dezember 2007, 15:02

Hallo Gerold,

ich habe meinen Code etwas umgebaut, bekomme die Druckfunktion aber nicht hin. Die Funktion OnPrintPage wird nur einmal aufgerufen, obwohl ich 2 Seiten übergebe. In der Druckvorschau steht auch "Page 1 of 2". Aus welcher Variable weiß wx, wie oft diese Funktion aufgerufen werden soll?
Ich benötige den Ausdruck immer in A3 Querformat. Das habe ich eingestellt.

Code: Alles auswählen

pdata.SetPaperId(wx.PAPER_A3)
pdata.SetOrientation(wx.LANDSCAPE)

Die Grafikgröße ist immer gleich (Höhe = 945, Breite = 1350). Kann ich diese Werte direkt übergeben?

Mawilo
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Samstag 15. Dezember 2007, 20:53

Mawilo hat geschrieben:Die Funktion OnPrintPage wird nur einmal aufgerufen

Hallo Mawilo!

Das hier dürfte helfen:

Code: Alles auswählen

    def HasPage(self, page_num):
        return page_num <= self.num_pages

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Samstag 15. Dezember 2007, 20:58

Mawilo hat geschrieben:Die Grafikgröße ist immer gleich (Höhe = 945, Breite = 1350). Kann ich diese Werte direkt übergeben?

Hallo Mawilo!

Durch ``self.page_height`` weißt du wieviel Platz du zur Verfügung hast. Dann noch die Höhe des Headers und die Höhe des Footers abziehen. Dann teilst du deine Details so auf, dass diese innerhalb dieser Höhe platz haben.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Samstag 15. Dezember 2007, 23:40

Hallo Gerold,

danke für Deine geduldigen Antworten :D
Ich muss noch ein bisschen am Format feilen, da ich unter Linux entwickelt habe, aber das Programm hauptsächlich unter Windows einsetzen werde. Es sieht aber schon sehr gut aus.
Eine Frage habe ich aber noch :wink:. Wenn ich die Druckvorschau und das Programm beende, erhalte ich in der Konsole keinen Prompt zurück, sondern muss erst mit Strg + Z den Prozess stoppen. Gibt es dazu noch einen Trick?

Viele Grüße
Mawilo
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Sonntag 16. Dezember 2007, 01:03

Mawilo hat geschrieben:Wenn ich die Druckvorschau und das Programm beende, erhalte ich in der Konsole keinen Prompt zurück, sondern muss erst mit Strg + Z den Prozess stoppen.

Hallo Mawilo!

Das könnte daran schuld sein:

Code: Alles auswählen

    def OnPrintPage(self, page):
        dc = self.GetDC()
        frame = MainFrame()
        frame.paintData(dc)

Du holst dir hier noch einmal eine neu initialisierte Frameinstanz. Und eine wx.App beendet sich per Definition erst, wenn kein Frame mehr existiert. Kannst du nicht die Frameinstanz an __init__ der MyPrintout-Klasse übergeben?

Ein ``frame.Destroy()`` würde dein Problem zwar sofort lösen, aber lieber wäre es mir, wenn du die Frameinstanz beim Erstellen der MyPrintout-Instanz übergeben würdest.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder