Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 24 - Grafikausgabe |
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): |
|
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 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: |
|
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 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. |
|
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 24.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 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. |
|
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. |
|
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 |
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
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 |
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 |