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

24.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 Rahmenprogramm eingebettet werden (auf der DVD 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 24.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 24.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 

24.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 24.5: Ausgabe von Linien

Abbildung 24.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, dass 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 selbst definiertes Füllmuster zu verwenden.

 Hinweis 

24.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 24.6: Ausgabe von Rechtecken

Abbildung 24.4: Ausgabe von Rechtecken

24.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, dass 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 Abschluss 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.Polygon

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 24.7: Ausgabe eines Polygons

Abbildung 24.5: Ausgabe eines Polygons

An diesem Beispiel lässt sich ein potenzielles 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ässt, insbesondere, wenn man bedenkt, dass der obere Rand des Buchstabens 50 Pixel vom Fensterrand entfernt ist. Der Grund dafür ist, dass 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 

24.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 Spezialisierung 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 hineinpasst.

 Hinweis 

Dass 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 24.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 24.6: Ausgabe von Kreisen

24.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ässt 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 24.9: Ausgabe von Kreisbögen

Abbildung 24.7: Ausgabe von Kreisbögen


 Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0
 <<    <     >    >>   API  © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de