From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+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 DVD haben diese Dateien die Erweiterung
+.inc):
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 23 - Grafikausgabe
+
+
+
+
+
+23.3 Elementare Grafikroutinen
+
+
+
+
+
+
+
+
+
+
+
+
+![]()
+
+
+
+![]()
+
+
+
+
+
+ Hinweis
+
+
+
+
+Listing 23.4: Rahmenprogramm für nachfolgende Beispiele
+
+
+
+
+
+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
+
+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: |
+
+
|
+![]() |
+
+
+
++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 | +
+ +
+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, 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 selbstdefiniertes +Füllmuster zu verwenden. |
+
+
|
+![]() |
+
+
+
++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 | +
+ +
+Abbildung 23.4: Ausgabe von Rechtecken
+ + + + ++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: |
+
+
|
+![]() |
+
+
+
++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 | +
+ +
+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, 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. |
+
+
|
+![]() |
+
+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. |
+
+
|
+![]() |
+
+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 | +
+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
+ + + + ++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 | +
+ +
+Abbildung 23.7: Ausgabe von Kreisbögen
+| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |