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

## 23.3 Elementare Grafikroutinen

- 23.3 Elementare Grafikroutinen
  - 23.3.1 Linie
  - 23.3.2 Rechteck
  - 23.3.3 Polygon
  - 23.3.4 Kreis
  - 23.3.5 Kreisbogen

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

- Die Klasse `GrafikRahmen` ist aus `Frame` abgeleitet, um ein Top-Level-Window darzustellen.
- Sie enthält eine statische Methode `main`, die als Eintrittspunkt für das Programm dient und das Fensterobjekt erzeugt.
- Der Konstruktor der Klasse enthält drei Methodenaufrufe, `setBackground`, `setSize` und `setVisible`, um die Farbe des Fensterhintergrunds und seine Größe einzustellen und das Fenster auf dem Bildschirm sichtbar zu machen.
- Weiterhin enthält der Konstruktor einen Aufruf von `addWindowListener`, mit dem ein `WindowClosingAdapter` zum Schließen des Fensters hinzugefügt wird.
- Schließlich gibt es eine Methode `paint`, die hier noch leer ist, aber in den nachfolgenden Beispielen dieses Kapitels den Aufruf verschiedener Grafikroutinen zeigt.

### 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
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de