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

23.3 Elementare Grafikroutinen



Die Klasse Graphics stellt neben vielen anderen Funktionen auch eine Sammlung von linienbasierten Zeichenoperationen zur Verfügung. Diese sind zur Darstellung von einfachen Linien, Rechtecken oder Polygonen sowie von Kreisen, Ellipsen und Kreisabschnitten geeignet. Wir wollen im folgenden jede dieser Funktionsgruppen vorstellen und ihre Anwendung an einem Beispiel zeigen.

Um nicht jeweils eine komplette Klassendefinition angeben zu müssen, werden wir in den folgenden Beispielen jeweils nur die Implementierung der paint-Methode zeigen. Diese könnte dann beispielsweise in das folgende Programm eingebettet werden (auf der CD haben diese Dateien die Erweiterung .inc):

 Hinweis 

001 /* GrafikBeispiel.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class GrafikBeispiel
007 extends Frame
008 {
009   public static void main(String[] args)
010   {
011     GrafikBeispiel wnd = new GrafikBeispiel();
012   }
013 
014   public GrafikBeispiel()
015   {
016     super("GrafikBeispiel");
017     addWindowListener(new WindowClosingAdapter(true));
018     setBackground(Color.lightGray);
019     setSize(300,200);
020     setVisible(true);
021   }
022 
023   public void paint(Graphics g)
024   {
025     //wird in den folgenden Beispielen überlagert
026   }
027 }
GrafikBeispiel.java
Listing 23.4: Rahmenprogramm für nachfolgende Beispiele

Da die paint-Methode in diesem Programm noch keine Ausgabeoperationen enthält, erzeugt das Programm lediglich ein leeres Fenster mit dem Titel »Grafikbeispiel«:

Abbildung 23.2: Ein einfaches Fenster

Das Beispielprogramm GrafikBeispiel ist so ungefähr der kleinstmögliche Rahmen, den man für ein AWT-basiertes Java-Programm vorgeben kann, wenn es ein einzelnes Fenster enthalten und beim Schließen desselben automatisch beendet werden soll. Es besteht aus folgenden Komponenten:

 Hinweis 

23.3.1 Linie

public void drawLine(int x1, int y1, int x2, int y2)
java.awt.Graphics

Zieht eine Linie von der Position (x1,y1) zur Position (x2,y2). Beide Punkte dürfen an beliebiger Stelle im Fenster liegen, das Einhalten einer bestimmten Reihenfolge ist nicht erforderlich. Teile der Ausgabe, die außerhalb des darstellbaren Bereichs liegen, werden, wie in grafikorientierten Systemen üblich, unterdrückt.

Das folgende Beispiel zeichnet eine Reihe von gleich hohen Linien, deren horizontaler Abstand durch einen Zufallszahlengenerator bestimmt wird. Das Ergebnis hat dadurch Ähnlichkeit mit einem Barcode (ist aber keiner):

001 /* Linien.inc */
002 
003 public void paint(Graphics g)
004 {
005   int i;
006   int x = 80;
007 
008   for (i=0; i<60; ++i) {
009     g.drawLine(x,40,x,100);
010     x += 1+3*Math.random();
011   }
012 }
Linien.inc
Listing 23.5: Ausgabe von Linien

Abbildung 23.3: Ausgabe von Linien

Die Methode drawLine zeichnet Linien grundsätzlich mit einer Dicke von einem Pixel. Die hier angezeigten unterschiedlich breiten Linien kommen dadurch zustande, daß zwei oder mehr Linien direkt nebeneinander ausgegeben werden. Das ist die einfachste Möglichkeit, Linien darzustellen, die dicker als 1 Pixel sind. Leider gibt es keine einfache Möglichkeit, gestrichelte oder gepunktete Linien zu zeichnen oder ein selbstdefiniertes Füllmuster zu verwenden.

 Hinweis 

23.3.2 Rechteck

public void drawRect(int x, int y, int width, int height)
java.awt.Graphics

Zeichnet ein Rechteck der Breite width und der Höhe height, dessen linke obere Ecke an der Position (x,y) liegt. Eine größere Breite dehnt das Rechteck nach rechts aus, eine größere Höhe nach unten.

Eine Variante von drawRect ist die Methode drawRoundRect:

public void drawRoundRect(
   int x, int y,
   int width, int height,
   int arcWidth, int arcHeight
)
java.awt.Graphics

Gegenüber drawRect sind hier die Parameter arcWidth und arcHeight dazugekommen. Sie bestimmen den horizontalen und vertikalen Radius des Ellipsenabschnitts, der zur Darstellung der runden »Ecke« verwendet wird.

Das folgende Beispiel zeichnet eine Kette von nebeneinanderliegenden Rechtecken, deren Größe durch einen Zufallszahlengenerator bestimmt wird. Der Zufallszahlengenerator entscheidet auch, ob ein Rechteck an der Ober- oder Unterseite seines Vorgängers festgemacht wird:

001 /* Rechtecke.inc */
002 
003 public void paint(Graphics g)
004 {
005   int x = 10, y = 80;
006   int sizex, sizey = 0;
007 
008   while (x < 280 && y < 180) {
009     sizex = 4 + (int) (Math.random() * 9);
010     if (Math.random() > 0.5) {
011       y += sizey;
012       sizey = 4 + (int) (Math.random() * 6);
013     } else {
014       sizey = 4 + (int) (Math.random() * 6);
015       y -= sizey;
016     }
017     g.drawRect(x,y,sizex,sizey);
018     x += sizex;
019   }
020 }
Rechtecke.inc
Listing 23.6: Ausgabe von Rechtecken

Abbildung 23.4: Ausgabe von Rechtecken

23.3.3 Polygon

Mit Hilfe der Methode drawPolygon ist es möglich, Linienzüge zu zeichnen, bei denen das Ende eines Elements mit dem Anfang des jeweils nächsten verbunden ist:

public void drawPolygon(int[] arx, int[] ary, int cnt)
java.awt.Graphics

drawPolygon erwartet drei Parameter. Der erste ist ein Array mit einer Liste der x-Koordinaten und der zweite ein Array mit einer Liste der y-Koordinaten. Beide Arrays müssen so synchronisiert sein, daß ein Paar von Werten an derselben Indexposition immer auch ein Koordinatenpaar ergibt. Die Anzahl der gültigen Koordinatenpaare wird durch den dritten Parameter festgelegt.

Im Gegensatz zum JDK 1.0 wird das Polygon nach Abschluß der Ausgabe automatisch geschlossen. Falls der erste und der letzte Punkt nicht identisch sind, werden diese durch eine zusätzliche Linie miteinander verbunden. Soll dagegen ein nichtgeschlossenes Polygon gezeichnet werden, so kann dazu die Methode drawPolyline verwendet werden:

 Hinweis 

public void drawPolyline(int[] arx, int[] ary, int cnt)
java.awt.Graphics

Eine zweite Variante, Polygone zu zeichnen, besteht darin, zunächst ein Objekt der Klasse Polygon zu konstruieren und dieses dann an drawPolygon zu übergeben. Polygon besitzt zwei Konstruktoren, von denen einer parameterlos ist und der andere dieselben Parameter wie die oben beschriebene Methode drawPolygon besitzt:

public void Polygon()

public void Polygon(int[] arx, int[] ary, int cnt)
java.awt.Graphics

Mit Hilfe der Methode addPoint kann ein Polygon um weitere Punkte erweitert werden. Schließlich kann das fertige Polygon an die Methode drawPolygon übergeben werden, die dann wie folgt aufzurufen ist:

public void drawPolygon(Polygon p)
java.awt.Graphics

Das folgende Beispiel gibt den Buchstaben »F« mit Hilfe eines geschlossenen Polygons aus:

001 /* Polygon.inc */
002 
003 public void paint(Graphics g)
004 {
005   int[] arx = {50,50,120,120,80,80,100,100,80,80};
006   int[] ary = {170,40,40,70,70,100,100,130,130,170};
007 
008   g.drawPolygon(arx,ary,arx.length);
009 }
Polygon.inc
Listing 23.7: Ausgabe eines Polygons

Abbildung 23.5: Ausgabe eines Polygons

An diesem Beispiel läßt sich ein potentielles Problem bei der Angabe von x- und y-Koordinaten zur Bestimmung einzelner Punkte in einem Fenster erkennen. Obwohl das Fenster durch Aufruf der Methode setSize eine Größe von 300*200 Pixeln hat, ist die untere Kante des »F« bereits sehr viel näher am unteren Rand des Fensters, als dessen y-Wert von 170 vermuten läßt, insbesondere, wenn man bedenkt, daß der obere Rand des Buchstabens 50 Pixel vom Fensterrand entfernt ist. Der Grund dafür ist, daß die Größenangabe für setSize die Größe des kompletten Fensters festlegt und damit auch den erforderlichen Platz für die Titelleiste und gegebenenfalls das Menü einschließt. Der zur Ausgabe zur Verfügung stehende Client-Bereich ist daher in aller Regel deutlich kleiner. Wir werden später noch lernen, wie die exakte Größe des Client-Bereichs bestimmt werden kann.

 Warnung 

23.3.4 Kreis

Die Graphics-Klasse von Java erlaubt sowohl das Zeichnen von Kreisen als auch von Ellipsen und Kreisabschnitten. Ein Kreis wird dabei als Verallgemeinerung einer Ellipse angesehen, und beide Objekte werden mit der Methode drawOval gezeichnet:

public void drawOval(int x, int y, int width, int height)
java.awt.Graphics

Anders als in anderen Grafiksystemen werden bei dieser Methode nicht der Mittelpunkt und der Radius des Kreises angegeben, sondern die übergebenen Parameter spezifizieren ein Rechteck der Größe width und heigth, dessen linke obere Ecke an der Position (x,y) liegt. Gezeichnet wird dann der größte Kreis, der vollständig in das Rechteck hineinpaßt.

 Hinweis 

Daß diese Vorgehensweise zwar untypisch ist, aber durchaus ihre Vorteile haben kann, zeigt das folgende Beispiel:

001 /* Kreise.inc */
002 
003 public void paint(Graphics g)
004 {
005   int r = 8;
006   int i, j;
007   int x, y;
008 
009   for (i=1; i<=10; ++i) {
010     x = 150 - r * i;
011     y = (int) (40 + (i - 1) * 1.7321 * r);
012     for (j=1; j<=i; ++j) {
013       g.drawOval(x,y,2*r,2*r);
014       x += 2 * r;
015     }
016   }
017 }
Kreise.inc
Listing 23.8: Ausgabe von Kreisen

Das Programm gibt dabei eine Pyramide von Kreisen aus. Da die an drawOval übergebenen Parameter bereits das umgebende Rechteck bezeichnen, kann die Figur wie eine Pyramide aus Rechtecken dargestellt werden:

Abbildung 23.6: Ausgabe von Kreisen

23.3.5 Kreisbogen

Ein Kreisbogen ist ein zusammenhängender Abschnitt der Umfangslinie eines Kreises. Er kann mit der Methode drawArc gezeichnet werden:

public void drawArc(
   int x, int y, int width, int height,
   int startAngle, int arcAngle
)
java.awt.Graphics

Die ersten vier Parameter bezeichnen dabei den Kreis bzw. die Ellipse so, wie dies auch bei drawOval der Fall war. Mit startAngle wird der Winkel angegeben, an dem mit dem Kreisabschnitt begonnen werden soll, und arcAngle gibt den zu überdeckenden Bereich an. Dabei bezeichnet ein Winkel von 0 Grad die 3-Uhr-Position, und positive Winkel werden entgegen dem Uhrzeigersinn gemessen. Als Einheit wird Grad verwendet und nicht das sonst übliche Bogenmaß.

Das folgende Beispiel zeichnet durch wiederholten Aufruf der Methode drawArc eine Ellipse mit einer gestrichelten Umfangslinie. Ein Aufruf zeichnet dabei jeweils 4 Grad der Ellipse und läßt dann eine Lücke von 3 Grad, bevor das nächste Stück gezeichnet wird:

001 /* KreisBoegen.inc */
002 
003 public void paint(Graphics g)
004 {
005   int line = 4;
006   int gap = 3;
007   int angle = 0;
008 
009   while (angle < 360) {
010     g.drawArc(20,40,250,140,angle,line);
011     angle += gap + line;
012   }
013 }
KreisBoegen.inc
Listing 23.9: Ausgabe von Kreisbögen

Abbildung 23.7: Ausgabe von Kreisbögen


 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