Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 3. Auflage
 <<    <     >    >>   API  Kapitel 26 - Drucken

26.2 Drucken mit dem JDK 1.1



26.2.1 Grundlagen

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, 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 (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, 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.

26.2.2 Seitenweise Ausgabe

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 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.

 Warnung 

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 muß Annahmen über die Papier- und Randgröße machen. 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 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.

 Warnung 

26.2.3 Plazierung des Codes zur Druckausgabe

Es gibt grundsätzlich zwei Möglichkeiten, die Druckausgabe im Programm zu plazieren. 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 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 zuvor besprochen bestimmen. Die Methode müßte dann nicht so programmiert werden, daß 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, daß Programmcode zum Erstellen der Ausgabe möglicherweise doppelt vorhanden ist und doppelt gepflegt werden muß.

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
Listing 26.1: Ausdruck einer Testseite

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, 3. Auflage, Addison Wesley, Version 3.0.1
 <<    <     >    >>   API  © 1998-2003 Guido Krüger, http://www.javabuch.de