|
Seit der Version 1.1 kann in Java gedruckt werden! Das ist deshalb bemerkenswert, weil es in den Vorgängerversionen keine Möglichkeit gab, dies zu tun. Im Laufe der Zeit entwickelten sich zwar einige inkompatible Erweiterungen, jedoch konnte sich keine von ihnen auf breiter Front durchsetzen.
Um so erfreulicher ist es, daß das Druck-API der Version 1.1 relativ übersichtlich gehalten wurde und leicht zu verstehen ist. Es gibt zwar einige Restriktionen und Besonderheiten, die beim Erstellen von Druckausgaben zu Problemen führen können, aber für einfache Ausdrucke von Text und Grafik ist die Schnittstelle recht gut geeignet.
Grundlage der Druckausgabe ist die Methode getPrintJob der Klasse Toolkit:
public PrintJob getPrintJob( Frame frame, String jobtitle, Properties props ) |
java.awt.Toolkit |
Sie liefert ein Objekt des Typs PrintJob, das zur Initialisierung eines Druckjobs verwendet werden kann. Ein Aufruf von getPrintJob führt gleichzeitig dazu, daß ein plattformspezifischer Druckdialog aufgerufen wird, der vom Anwender bestätigt werden muß. Bricht der Anwender den Druckdialog ab, liefert getPrintJob den Rückgabewert null, andernfalls wird der Drucker initialisiert und die Ausgabe kann beginnen.
Die Klasse PrintJob stellt einige Methoden zur Verfügung, die für den Ausdruck benötigt werden:
public Graphics getGraphics() public Dimension getPageDimension() public int getPageResolution() public abstract void end() |
java.awt.PrintJob |
Die wichtigste von ihnen ist getGraphics. Sie liefert den Devicekontext zur Ausgabe auf den Drucker. Der Rückgabewert ist ein Objekt vom Typ PrintGraphics, das aus Graphics abgeleitet ist und wie ein normaler Devicekontext verwendet werden kann, der beispielsweise an paint übergeben wird. Mit Hilfe des von getGraphics zurückgegebenen Devicekontexts können alle Grafik- und Textroutinen, die auch in Graphics zur Verfügung stehen, verwendet werden. Bezüglich der Verwendung von Farben gilt scheinbar, daß diese bei den linienbezogenen Ausgaberoutinen nicht unterstützt werden. Hier wird alles schwarz gezeichnet, was nicht den Farbwert (255, 255, 255) hat. Im Gegensatz dazu stellen die Füllfunktionen Farben (auf einem Schwarzweiß-Drucker) als Grauwerte dar. Dabei kann - je nach Druckertyp - auch Weiß eine Vollfarbe sein und dahinter liegende Objekte verdecken.
Ein wichtiger Unterschied zu einem bildschirmbezogenen Devicekontext besteht darin, daß jeder Aufruf von getGraphics eine neue Druckseite beginnt. Die fertige Druckseite wird durch Aufruf von dispose an den Drucker geschickt. Für den Aufbau der Seite, das Ausgeben von Kopf- oder Fußzeilen, die Seitennumerierung und ähnliche Dinge ist die Anwendung selbst verantwortlich. Die Methode end ist aufzurufen, wenn der Druckjob beendet ist und alle Seiten ausgegeben wurden. Dadurch werden alle belegten Ressourcen freigegeben und die Druckerschnittstelle geschlossen.
Bei der Druckausgabe ist es wichtig zu wissen, wie groß die Abmessungen des Ausgabegeräts sind. Die hierzu angebotenen Methoden getPageDimension und getPageResolution sind in der aktuellen Version leider vollkommen unbrauchbar. getPageResolution liefert die tatsächliche Auflösung des Druckers in Pixel per Zoll (also z.B. 600 für einen Laserjet IV), während getPageDimension die Anzahl der Pixel liefert, die sich errechnet, wenn man ein Blatt Papier im US-Letter-Format (8,5 mal 11 Zoll) mit 72 dpi Auflösung darstellen würde. Leider erfolgt die Druckausgabe nicht mit 72 dpi, sondern in der aktuellen Bildschirmauflösung, wie sie von der Methode getScreenResolution der Klasse Toolkit geliefert wird. Da diese typischerweise bei 120 dpi liegt, füllen die von getPageResolution gelieferten Abmessungen nur etwa 60 % einer Seite. |
![]() |
|
![]() |
Derzeit gibt es keine portable Lösung für dieses Problem. Ein Workaround besteht darin, die Papiergröße als fest anzunehmen (beispielsweise DIN A4 mit 21,0*29,7 cm), davon den nicht bedruckbaren Rand abzuziehen, das Ergebnis durch 2,54 (Anzahl cm je Zoll) zu teilen und mit der Auflösung von 120 dpi malzunehmen. Wir werden weiter unten ein Beispiel sehen, in dem diese Technik angewandt wird. Portabel ist sie allerdings nicht, denn das Programm muß Annahmen über die Papier- und Randgröße beisteuern. Es bleibt demnach zu hoffen, daß die nachfolgenden Versionen des JDK die Bestimmung der Abmessungen auf eine flexiblere Weise ermöglichen.
Durch die fixe Einstellung der Ausgabeauflösung ergibt sich ein weiteres Problem. So kann ein Drucker mit 600 dpi aus Java heraus nämlich nur mit der aktuellen Bildschirmauflösung (z.B. 120 dpi) angesteuert werden. Das bedeutet zwar nicht automatisch, daß Schriften oder schräge Linien mit Treppenmustern dargestellt werden, denn sie werden meist als Vektorgrafiken an den Drucker übergeben. Allerdings können beispielsweise keine Pixelgrafiken in der aktuellen Druckerauflösung ausgegeben werden, denn die Positioniergenauigkeit eines einzelnen Pixels liegt bei 120 dpi. Eine Lösung für dieses Problem ist derzeit nicht bekannt. |
![]() |
|
![]() |
Es gibt grundsätzlich zwei Möglichkeiten, die Druckausgabe im Programm zu plazieren. Einmal kann die normale paint-Methode dazu verwendet werden, sowohl Bildschirm- als auch Druckausgaben zu realisieren. Bei einem Aufruf der Methode print oder printAll der Klasse Component wird nämlich ein PrintJob erstellt, daraus der Grafikkontext beschafft und an paint übergeben:
public void print(Graphics g) public void printAll(Graphics g) |
java.awt.Component |
Auf diese Weise kann bereits ohne zusätzliche Erweiterungen eine einfache Druckausgabe realisiert werden, die der Bildschirmausgabe relativ ähnlich sieht. Im Gegensatz zu print gibt printAll dabei nicht nur die aktuelle Komponente, sondern die komplette Container-Hierarchie eines komplexen Dialogs aus. Soll innerhalb von paint unterschieden werden, ob auf den Bildschirm oder den Drucker ausgegeben wird, so kann mit dem Ausdruck g instanceof PrintGraphics das übergebene Graphics-Objekt g auf Zugehörigkeit zur Klasse PrintGraphics getestet werden.
Die zweite Möglichkeit, die Druckausgabe zu plazieren, besteht darin, eine eigene Methode zu schreiben, die nur für die Ausgabe auf den Drucker verantwortlich ist. Diese könnte zunächst den PrintJob und das PrintGraphics-Objekt beschaffen und anschließend die Abmessungen der Ausgabefläche wie oben besprochen bestimmen. Die Methode wäre dann nicht darauf angewiesen, daß sie sowohl für die Bildschirm- als auch für die Druckausgabe vernünftige Resultate liefern muß, sondern könnte ihre Ausgaben für die Druckausgabe optimieren. Der Nachteil bei dieser Löung ist allerdings, daß möglicherweise Code zum Erstellen der Ausgabe doppelt vorhanden ist und doppelt gepflegt werden muß.
Das nachfolgende Listing kombiniert beide Varianten und demonstriert dies am Ausdruck einer Testseite. Das Programm erstellt ein Hauptfenster und ruft zwei Sekunden später die Methode printTestPage zur Druckausgabe auf. Darin wird zunächst ein PrintJob erzeugt und dann gemäß dem oben beschriebenen Verfahren die Ausgabegröße ermittelt. Anschließend wird der Grafikkontext beschafft und ein Rahmen, einige Textzeilen mit Angaben zu den Metriken und eine Graustufenmatrix werden ausgegeben. Nach Ende der Druckausgabe wird die Seite mit dispose ausgegeben und der Druckjob mit end geschlossen. Der Code für die Darstellung der Graustufenmatrix wurde in der Methode paintGrayBoxes implementiert und wird von der Bildschirm- und Druckausgabe gemeinsam verwendet:
|
![]() |
|
![]() |
Die Bildschirmausgabe des Programms kann Abbildung 15.8 entnommen werden. Die Druckausgabe sieht ähnlich aus, enthält aber zusätzlich noch einen Rahmen und die Textausgabe mit den Informationen zu den Druckmetriken.
Abbildung 15.8: Das Programm zur Druckausgabe
Im JDK 1.2 wurde das Konzept der Druckausgabe erneut geändert. Anstelle der oben beschriebenen Klassen werden nun die Klassen und Interfaces aus dem Paket java.awt.print verwendet (beispielsweise PrinterJob, Printable und Pageable). Leider war das neue Drucksystem mit der Ausgabe der Version 1.2 noch nicht stabil genug, um hier ausführlich beschrieben zu werden. Im Usenet wurden eine Vielzahl von Problemen und Schwierigkeiten mit unterschiedlichen Druckertypen und Betriebssystemen diskutiert. Wir werden die Neuerungen daher hier noch nicht behandeln, sondern sie zu gegebener Zeit in der Online-Version des Buchs aufgreifen. |
![]() |
|
![]() |
|
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com |