Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 5. Auflage |
<< | < | > | >> | API | Kapitel 26 - Drucken |
Das Druck-API der Version 1.1 ist recht übersichtlich und leicht zu verstehen. 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 dennoch 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, dass ein plattformspezifischer Druckdialog aufgerufen wird, der vom Anwender bestätigt werden muss. 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 (so, wie er beispielsweise auch 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, dass 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, dass 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 im JDK 1.1 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 später ein Beispiel sehen, in dem diese Technik angewandt wird. Portabel ist sie allerdings nicht, denn das Programm muss Annahmen über die Papier- und Randgröße machen. Es bleibt demnach zu hoffen, dass 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, dass Schriften oder schräge Linien mit Treppenmustern dargestellt werden, denn sie werden meist als Vektorgrafiken an den Drucker übergeben. Allerdings können Pixelgrafiken beispielsweise nicht 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 platzieren. Einmal kann die 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 zwischen Bildschirm- und Druckerausgabe unterschieden werden, 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 platzieren, 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 zuvor besprochen bestimmen. Die Methode müsste dann nicht so programmiert werden, dass sie für Bildschirm- und Druckausgabe vernünftige Resultate liefert, sondern könnte ihre Ausgaben ausschließlich für die Druckausgabe optimieren. Der Nachteil bei dieser Löung ist natürlich, dass Programmcode zum Erstellen der Ausgabe möglicherweise doppelt vorhanden ist und doppelt gepflegt werden muss.
Das nachfolgende Listing kombiniert beide Varianten und zeigt den 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 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:
001 /* Listing2601.java */ 002 003 import java.awt.*; 004 import java.awt.event.*; 005 006 public class Listing2601 007 extends Frame 008 { 009 public static void main(String[] args) 010 { 011 Listing2601 wnd = new Listing2601(); 012 } 013 014 public Listing2601() 015 { 016 super("Drucken"); 017 addWindowListener(new WindowClosingAdapter(true)); 018 setBackground(Color.lightGray); 019 setSize(400,400); 020 setVisible(true); 021 //Ausdruck in 2 Sekunden starten 022 try { 023 Thread.sleep(2000); 024 } catch (InterruptedException e) { 025 //nichts 026 } 027 printTestPage(); 028 } 029 030 public void paint(Graphics g) 031 { 032 paintGrayBoxes(g, 40, 50); 033 } 034 035 public void printTestPage() 036 { 037 PrintJob pjob = getToolkit().getPrintJob( 038 this, 039 "Testseite", 040 null 041 ); 042 if (pjob != null) { 043 //Metriken 044 int pres = pjob.getPageResolution(); 045 int sres = getToolkit().getScreenResolution(); 046 Dimension d2 = new Dimension( 047 (int)(((21.0 - 2.0) / 2.54) * sres), 048 (int)(((29.7 - 2.0) / 2.54) * sres) 049 ); 050 //Ausdruck beginnt 051 Graphics pg = pjob.getGraphics(); 052 if (pg != null) { 053 //Rahmen 054 pg.drawRect(0, 0, d2.width, d2.height); 055 //Text 056 pg.setFont(new Font("TimesRoman",Font.PLAIN,24)); 057 pg.drawString("Testseite",40,70); 058 pg.drawString( 059 "Druckerauflösung : " + pres + " dpi", 060 40, 061 100 062 ); 063 pg.drawString( 064 "Bildschirmauflösung : " + sres + " dpi", 065 40, 066 130 067 ); 068 pg.drawString( 069 "Seitengröße : " + d2.width + " * " + d2.height, 070 40, 071 160 072 ); 073 //Graustufenkästchen 074 paintGrayBoxes(pg, 40, 200); 075 //Seite ausgeben 076 pg.dispose(); 077 } 078 pjob.end(); 079 } 080 } 081 082 private void paintGrayBoxes(Graphics g, int x, int y) 083 { 084 for (int i = 0; i < 16; ++i) { 085 for (int j = 0; j < 16; ++j) { 086 int level = 16 * i + j; 087 g.setColor(Color.black); 088 g.drawRect(x + 20 * j, y + 20 * i, 20, 20); 089 g.setColor(new Color(level, level, level)); 090 g.fillRect(x + 1 + 20 * j, y + 1 + 20 * i, 19, 19); 091 } 092 } 093 } 094 } |
Listing2601.java |
Die Bildschirmausgabe des Programms kann Abbildung 26.1 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 26.1: Das Programm zur Druckausgabe
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 5. Auflage, Addison Wesley, Version 5.0.2 |
<< | < | > | >> | API | © 1998, 2007 Guido Krüger & Thomas Stark, http://www.javabuch.de |