11.4Geometrische Objekte
Die Java-Bibliothek repräsentiert geometrische Formen durch eine Schnittstelle Shape. Konkrete Formen sind etwa Linien, Polygone oder Kurven, die die Bibliothek durch konkrete Implementierungen der Schnittstelle realisiert. Für uns gibt es damit zwei Möglichkeiten, Zeichenoperationen zu tätigen: zum einen indem wir Objekte aufbauen und diese dann zeichnen lassen und zum anderen über die speziellen Zeichenmethoden von Graphics, wie die bekannten Methoden drawLine(…) und drawRect(…). Objekte bieten den Vorteil, dass sie sich in einer Datenstruktur sammeln lassen, und die Shape-Objekte warten auch noch mit einer ganzen Reihe interessanter Methoden auf.
Beginnen wir mit einem Programm, das eine Linie als Formobjekt zeichnet:
Listing 11.5com/tutego/insel/ui/g2d/First2D.java, First2DDemo
@Override protected void paintComponent( Graphics g ) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.draw( new Line2D.Double( 10, 10, getWidth() – 10, getHeight() – 10 ) );
}
public static void main( String[] args ) {
JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.setSize( 200, 120 );
f.add( new First2D() );
f.setVisible( true );
}
}
Die Klasse Line2D.Double definiert das Linienobjekt, das draw(Shape) zeichnet (und fill(Shape) füllen würde). Die Methode draw(Shape), die es nur auf dem Graphics2D-Objekt und nicht bei der Basisklasse Graphics gibt, nimmt ein beliebiges Shape-Objekt und zeichnet es nach den aktuellen Einstellungen wie Muster oder Farbe. Da normalerweise die Ausgabe nicht weichgezeichnet ist, wir dies aber wünschen, setzen wir einen setRenderingHint(…). Die Argumente und die Methoden werden später näher beschrieben.
Abbildung 11.8Eine weiche Linie
extends Graphics
abstract void draw(Shape s)
Zeichnet die Form im aktuellen Graphics2D-Kontext. Die Attribute umfassen Clipping, Transformation, Zeichen, Zusammensetzung und Stift-(Stroke-)Attribute.
11.4.1Die Schnittstelle Shape
Die geometrischen Objekte, die die Schnittstelle java.awt.Shape implementieren, sind unter anderem:
RectangularShape mit den Unterklassen Arc2D, Ellipse2D, Rectangle2D und RoundRectangle2D sind Objekte, die in einem Rechteck eingefasst sind.
Fast alle Klassen sind abstrakt, und innen liegende Unterklassen implementieren die äußere Klasse mit den Genauigkeiten float und double. Ein Beispiel für Line2D haben wir im oberen Programm First2DDemo schon aufgeführt; die öffentliche konkrete innere Klasse mit der Genauigkeit double heißt Line2D.Double.
Abbildung 11.9Vererbungsbeziehungen der Unterklassen von Shape
Die Schnittstelle java.awt.Shape deklariert Operationen, die die Unterklassen passend implementieren:
contains(…): Testet, ob ein Punkt bzw. Rechteck in der Form ist.
getBounds(), getBounds2D(): Liefert den kleinsten Rahmen, der die Form vollständig enthält.
getPathItererator(…): Liefert einen PathIterator, der die äußeren Pfade entlangläuft.
intersects(…): Testet, ob ein Rechteck diese Form schneidet.
Abbildung 11.10getBounds() am Beispiel einiger Formen
[»]Hinweis
Es gibt in der Java-Bibliothek zwar Klassen wie Point, Point2D.Float und Point2D.Double, die Point2D erweitern, aber dies sind keine Shape-Objekte, und sie können nicht gezeichnet werden. Die Typen repräsentieren x/y-Koordinaten und finden sich nur als Parametertyp, etwa zum Aufbau von Linien, Kurven oder Gradienten. Auch für Text gibt es keine spezielle Shape-Implementierung. Um Text zu zeichnen, wird weiterhin die Methode drawString(string, x, y) verwendet, allerdings sind die Koordinaten Graphis2D-taugliche Fließkommazahlen vom Typ float.
11.4.2Pfade *
Ein Pfad besteht aus zusammengesetzten Segmenten, die miteinander verbunden sind. Die Segmente bestehen nicht wie bei Polygonen ausschließlich aus Linien, sondern können auch quadratische oder kubische Kurven sein. Die Klasse java.awt.geom.GeneralPath erbt von Path2D (die wiederum von Path2D.Float erbt) und hängt Schritt für Schritt die Segmente mit den Methoden lineTo(…), curveTo(…), quadTo(…) an und den Umriss anderer Formen mit append(PathIterator, boolean). Da der Startpunkt automatisch bei (0,0) liegt, setzt moveTo(…) ihn zum Start – oder auch später – um.
[zB]Beispiel
Zeichnen einer Linie als Pfad mit der 2D-API:
Graphics2D g2 = (Graphics2D) g;
GeneralPath p = new GeneralPath();
p.moveTo( 10f, 10f );
p.lineTo( 100f, 20f );
g2.setColor( Color.BLACK );
g2.draw( p );
}
Natürlich hätten wir in diesem Fall auch ein Line2D-Objekt nehmen können. Doch dieses Beispiel zeigt einfach, wie ein Pfad aufgebaut ist. Zunächst bewegen wir den Zeichenstift mit moveTo(float, float) auf eine Position, und anschließend zeichnen wir eine Linie mit lineTo(float, float). Ist der Pfad einmal gezogen, zeichnet draw(Shape) die Form, und fill(Shape) füllt das Objekt aus.
Um eine Kurve zu einem Punkt zu ziehen, nehmen wir quadTo(x1, x2, y2, y2) oder für Bézier-Kurven curveTo(x1, x2, y2, y2, y3, y3). Die Methoden erwarten Argumente vom Typ float oder double.