Galileo Computing :: Java 7 - Mehr als eine Insel - 10 Grafikprogrammierung
Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Neues in Java 7
2 Threads und nebenläufige Programmierung
3 Datenstrukturen und Algorithmen
4 Raum und Zeit
5 Dateien, Verzeichnisse und Dateizugriffe
6 Datenströme
7 Die eXtensible Markup Language (XML)
8 Dateiformate
9 Grafische Oberflächen mit Swing
10 Grafikprogrammierung
11 Netzwerkprogrammierung
12 Verteilte Programmierung mit RMI
13 RESTful und SOAP Web-Services
14 JavaServer Pages und Servlets
15 Applets
16 Datenbankmanagement mit JDBC
17 Technologien für die Infrastruktur
18 Reflection und Annotationen
19 Dynamische Übersetzung und Skriptsprachen
20 Logging und Monitoring
21 Java Native Interface (JNI)
22 Sicherheitskonzepte
23 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- openbook, ca. 21,3 MB
Buch bestellen
Ihre Meinung?

Spacer
Java 7 - Mehr als eine Insel von Christian Ullenboom
Das Handbuch zu den Java SE-Bibliotheken
Buch: Java 7 - Mehr als eine Insel

Java 7 - Mehr als eine Insel
Galileo Computing
1433 S., 2012, geb.
49,90 Euro, ISBN 978-3-8362-1507-7
Pfeil 10 Grafikprogrammierung
Pfeil 10.1 Grundlegendes zum Zeichnen
Pfeil 10.1.1 Die paint()-Methode für das AWT-Frame
Pfeil 10.1.2 Zeichnen von Inhalten auf ein JFrame
Pfeil 10.1.3 Auffordern zum Neuzeichnen mit repaint()
Pfeil 10.1.4 Java 2D-API
Pfeil 10.2 Einfache Zeichenmethoden
Pfeil 10.2.1 Linien
Pfeil 10.2.2 Rechtecke
Pfeil 10.2.3 Ovale und Kreisbögen
Pfeil 10.2.4 Polygone und Polylines
Pfeil 10.3 Zeichenketten schreiben und Fonts
Pfeil 10.3.1 Zeichenfolgen schreiben
Pfeil 10.3.2 Die Font-Klasse
Pfeil 10.3.3 Einen neuen Font aus einem gegebenen Font ableiten
Pfeil 10.3.4 Zeichensätze des Systems ermitteln *
Pfeil 10.3.5 Neue TrueType-Fonts in Java nutzen
Pfeil 10.3.6 Font-Metadaten durch FontMetrics *
Pfeil 10.4 Geometrische Objekte
Pfeil 10.4.1 Die Schnittstelle Shape
Pfeil 10.4.2 Kreisförmiges
Pfeil 10.4.3 Kurviges *
Pfeil 10.4.4 Area und die konstruktive Flächengeometrie *
Pfeil 10.4.5 Pfade *
Pfeil 10.4.6 Punkt in einer Form, Schnitt von Linien, Abstand Punkt/Linie *
Pfeil 10.5 Das Innere und Äußere einer Form
Pfeil 10.5.1 Farben und die Paint-Schnittstelle
Pfeil 10.5.2 Farben mit der Klasse Color
Pfeil 10.5.3 Die Farben des Systems über SystemColor *
Pfeil 10.5.4 Composite und Xor *
Pfeil 10.5.5 Dicke und Art der Linien von Formen bestimmen über Stroke *
Pfeil 10.6 Bilder
Pfeil 10.6.1 Eine Übersicht über die Bilder-Bibliotheken
Pfeil 10.6.2 Bilder mit ImageIO lesen
Pfeil 10.6.3 Ein Bild zeichnen
Pfeil 10.6.4 Programm-Icon/Fenster-Icon setzen
Pfeil 10.6.5 Splash-Screen *
Pfeil 10.6.6 Bilder im Speicher erzeugen *
Pfeil 10.6.7 Pixel für Pixel auslesen und schreiben *
Pfeil 10.6.8 Bilder skalieren *
Pfeil 10.6.9 Schreiben mit ImageIO
Pfeil 10.6.10 Asynchrones Laden mit getImage() und dem MediaTracker *
Pfeil 10.7 Weitere Eigenschaften von Graphics *
Pfeil 10.7.1 Eine Kopie von Graphics erstellen
Pfeil 10.7.2 Koordinatensystem verschieben
Pfeil 10.7.3 Beschnitt (Clipping)
Pfeil 10.7.4 Zeichenhinweise durch RenderingHints
Pfeil 10.7.5 Transformationen mit einem AffineTransform-Objekt
Pfeil 10.8 Drucken *
Pfeil 10.8.1 Drucken der Inhalte
Pfeil 10.8.2 Bekannte Drucker
Pfeil 10.9 Benutzerinteraktionen automatisieren, Robot und Screenshots *
Pfeil 10.9.1 Der Roboter
Pfeil 10.9.2 Automatisch in die Tasten hauen
Pfeil 10.9.3 Automatisierte Mausoperationen
Pfeil 10.9.4 Methoden zur Zeitsteuerung
Pfeil 10.9.5 Bildschirmabzüge (Screenshots)
Pfeil 10.9.6 Funktionsweise und Beschränkungen
Pfeil 10.9.7 MouseInfo und PointerInfo
Pfeil 10.10 Zum Weiterlesen

Galileo Computing - Zum Seitenanfang

10.4 Geometrische ObjekteZur nächsten Überschrift

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: einmal, indem wir Objekte aufbauen und diese dann zeichnen lassen, und zweitens ü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 Form-Objekt zeichnet:

Listing 10.7: com/tutego/insel/ui/g2d/First2Ddemo.java, First2DDemo

class First2DDemo extends JPanel
{
@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 First2DDemo() );
f.setVisible( true );
}
}

Die Klasse Line2D.Double definiert das Linien-Objekt, das draw() zeichnet (und fill() 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

Abbildung 10.9: Eine weiche Linie

abstract class java.awt.Graphics2D
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.

Galileo Computing - Zum Seitenanfang

10.4.1 Die Schnittstelle ShapeZur nächsten ÜberschriftZur vorigen Überschrift

Die geometrischen Objekte, die die Schnittstelle java.awt.Shape implementieren, sind unter anderem:

  • Line2D
  • RectangularShape mit den Unterklassen Arc2D, Ellipse2D, Rectangle2D und RoundRectangle2D
  • Polygon
  • QuadCurve2D
  • CubicCurve2D

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

Abbildung 10.10: Vererbungsbeziehungen der Unterklassen von Shape

Die Klassen Rectangle2D, RoundRectangle2D, Arc2D und Ellipse2D erben alle von der Klasse RectangularShape und sind dadurch Objekte, die von einer (mitunter virtuellen) rechteckigen Box umgeben sind. RectangularShape selbst ist abstrakt, gibt aber Methoden vor, die das umrahmende Rechteck verändern und abfragen.

Die Schnittstelle java.awt.Shape deklariert Operationen, die die Unterklassen passend implementieren:

  • contains(): Testet, ob ein Punkt 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

Abbildung 10.11: getBounds() am Beispiel einiger Formen

Hinweis

Es gibt in der Java-Bibliothek zwar Klassen wie Point sowie Point2D.Float und Point2D.Double, die Point2D erweitern, aber dies sind keine Shape-Objekte und 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.


Galileo Computing - Zum Seitenanfang

10.4.2 KreisförmigesZur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse java.awt.geom.Arc2D kümmert sich um Kreisbögen. Diese Bögen werden wie bei drawArc() in ein Rechteck eingepasst und haben einen Start- und Endwert. Zusätzlich kommt ein Parameter für den Typ des Bogens hinzu. Es gibt drei Typen:

  • Arc2D.OPEN: eine einfache Kreislinie
  • Arc2D.CHORD: Start- und Endpunkt des Bogens werden durch eine Linie verbunden.
  • Arc2D.PIE: Start- und Endpunkt des Bogens werden mit dem Mittelpunkt des Kreises verbunden.

Abbildung

Abbildung 10.12: Die drei Kreistypen

Listing 10.8: com/tutego/insel/ui/graphics/PanelWithArc.java, paintComponent()

@Override protected void paintComponent( Graphics g )
{
Shape arc = // x, y, w, h, start, extend, type
new Arc2D.Double( 100, 100, 60, 60, 30, 120, Arc2D.PIE );

((Graphics2D)g).draw( arc );
}

Galileo Computing - Zum Seitenanfang

10.4.3 Kurviges *Zur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse QuadCurve2D beschreibt quadratische Kurvensegmente. Dies sind Kurven, die durch zwei Endpunkte und durch dazwischenliegende Kontrollpunkte gegeben sind. CubicCurve2D beschreibt kubische Kurvensegmente, die durch zwei Endpunkte und zwei Kontrollpunkte definiert sind. Kubische Kurvensegmente werden auch Bézier-Kurven genannt.


Galileo Computing - Zum Seitenanfang

10.4.4 Area und die konstruktive Flächengeometrie *Zur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse Area definiert eine neue Form, die sich aus der Verknüpfung anderer Formen ergibt. Die Verknüpfungen sind Addition (Vereinigung), Subtraktion, Schnitt und Xor. Eine Zipfelmütze lässt sich auf diese Weise durch ein Shape mit dreieckiger Form, vereinigt mit einem Kreis, darstellen. Die wichtigsten Methoden sind:

class java.awt.geom.Area
implements Cloneable, Shape
  • Area()
  • Area(Shape s)
    Baut eine neue Geometrie auf, entweder leer oder mit einer vorgegebenen Form.
  • void add(Area rhs)
    Bildet eine Vereinigung der aktuellen Form mit der Form rhs.
  • void exclusiveOr(Area rhs)
    Bildet eine Xor-Verknüpfung mit der Form rhs.
  • void intersect(Area rhs)
    Bildet den Schnitt mit rhs.
  • void subtract(Area rhs)
    Zieht von der aktuellen Form die Form rhs ab.

Abbildung

Abbildung 10.13: Beispiele für konstruktive Flächengeometrie mit Rechteck und Kreis

Weitere Methoden sind transform(), reset(), contains(), getBounds() und ein paar weitere. Die Verknüpfungen werden auch CAG (Constructive Area Geometry), zu Deutsch konstruktive Flächengeometrie, genannt. Bei den Signaturen der CAG-Methoden ist zu bemerken, dass der Parametertyp Area und nicht Shape ist.


Galileo Computing - Zum Seitenanfang

10.4.5 Pfade *Zur nächsten ÜberschriftZur vorigen Überschrift

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 GeneralPath hängt Schritt für Schritt die Segmente mit den Methoden lineTo(), curveTo(), quadTo() an und den Umriss anderer Formen mit append(). Da der Startpunkt automatisch bei (0,0) liegt, setzt move() ihn zum Start – oder auch später – um.

Beispiel

Zeichnen einer Linie als Pfad mit der 2D-API:

protected void paintComponent( Graphics g )
{
Graphics2D g2 = (Graphics2D) g;
GeneralPath p = new GeneralPath();
p.moveTo( 10f, 10f );
p.lineTo( 100f, 20f );
g2.setColor( Color.BLACK );
g2.draw( p );
}

Abbildung

Abbildung 10.14: Klassendiagramm von Path2D

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() auf eine Position, und anschließend zeichnen wir eine Linie mit lineTo(). Ist der Pfad einmal gezogen, zeichnet draw() die Form, und fill() füllt das Objekt aus.

Um eine Kurve zu einem Punkt zu ziehen, nehmen wir quadTo() oder für Bézier-Kurven curveTo(). Die Methoden erwarten Argumente vom Typ float.

Windungsregel

Eine wichtige Eigenschaft der Pfade für gefüllte Objekte ist die Windungsregel (engl. winding rule). Diese Regel kann entweder WIND_NON_ZERO oder WIND_EVEN_ODD sein. Wenn Zeichenoperationen aus einer Form herausführen und wir uns dann wieder in der Figur befinden, sagt WIND_EVEN_ODD aus, dass dann innen und außen umgedreht wird. Wenn wir also zwei Rechtecke durch einen Pfad ineinander positionieren und der Pfad gefüllt wird, bekommt die Form in der Mitte ein Loch. Die Konstanten aus dem GeneralPath-Objekt (genauer gesagt sind sie aus der Oberklasse Path2D geerbt) werden der Methode setWindingRule() übergeben:

generalPath.setWindingRule( GeneralPath.WIND_NON_ZERO );

Windungsbeispiel

Das folgende Programm zeichnet ein blaues Rechteck mit GeneralPath.WIND_NON_ZERO und ein rotes Rechteck mit GeneralPath.WIND_EVEN_ODD. Mit der Konstanten WIND_NON_ZERO bei setWindingRule() wird das innere Rechteck mit ausgefüllt. Ausschlaggebend dafür, ob das innere Rechteck gezeichnet wird, ist die Anzahl der Schnittpunkte nach außen – »außen« heißt in diesem Fall, dass es unendlich viele Schnittpunkte gibt. Diese Regel wird aber nur dann wichtig, wenn wir mit nichtkonvexen Formen arbeiten. Solange sich die Linien nicht schneiden, ist dies kein Problem:

Listing 10.9: com/tutego/insel/ui/g2d/WindDemo.java, paintComponent()

protected void paintComponent( Graphics g )
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.clearRect( 0, 0, getSize().width-1, getSize().height-1 );
g2.setColor( Color.YELLOW );
g2.fill( new Rectangle( 70, 70, 130, 50 ) );
GeneralPath p;

// Erstes Rechteck
p = makeRect( 100, 80, 50, 50 );
p.setWindingRule( GeneralPath.WIND_NON_ZERO );
g2.setColor( Color.BLUE );
g2.fill( p );

// Zweites Rechteck
p = makeRect( 200, 80, 50, 50 );
p.setWindingRule( GeneralPath.WIND_EVEN_ODD );
g2.setColor( Color.RED );
g2.fill( p );
}

Die eigene statische Methode makeRect() definiert den Pfad für die Rechtecke mit den Mittelpunktkoordinaten x und y. Das erste Rechteck besitzt die Breite width sowie die Höhe height, und das innere Rechteck ist halb so groß:

Listing 10.10: com/tutego/insel/ui/g2d/WindDemo.java, makeRect()

static GeneralPath makeRect( int x, int y, int width, int height )
{
GeneralPath p = new GeneralPath();

p.moveTo( x + width/2, y – height/2 );
p.lineTo( x + width/2, y + height/2 );
p.lineTo( x – width/2, y + height/2 );
p.lineTo( x – width/2, y – height/2 );

// p.closePath();
p.moveTo( x + width/4, y – height/4 );
p.lineTo( x + width/4, y + height/4 );
p.lineTo( x – width/4, y + height/4 );
p.lineTo( x – width/4, y – height/4 );

return p;
}

Mit moveTo() bewegen wir uns zum ersten Punkt. Die anschließenden lineTo()-Direktiven formen das Rechteck. Die Form muss nicht geschlossen werden, da dies mit fill() automatisch geschieht. Mit closePath() können wir jedoch noch zusätzlich schließen; wenn wir das Objekt zeichnen, ist dies selbstverständlich notwendig. Dieses Beispiel macht durch das innere Rechteck deutlich, dass die Figuren eines GeneralPath-Objekts nicht zusammenhängend sein müssen. Das innere Rechteck wird genauso gezeichnet wie das äußere.

Abbildung

Abbildung 10.15: Die Windungsregeln WIND_NO_ZERO und WIND_EVEN_ODD


Galileo Computing - Zum Seitenanfang

10.4.6 Punkt in einer Form, Schnitt von Linien, Abstand Punkt/Linie *Zur vorigen Überschrift

Die unterschiedlichen Klassen für die geometrischen Formen besitzen Methoden, um zum Beispiel festzustellen, ob ein Punkt in einer Form liegt.

interface java.awt.Shape
  • boolean contains(int x, int y )
  • boolean contains(Point2D p)
    Liefert true, wenn der Punkt in der Form liegt.
  • boolean contains(int x, int y, int w, int h)
  • boolean contains(Rectangle2D r)
    Liefert true, wenn das beschriebene Rechteck komplett in der Form liegt.

Besonders praktisch ist die Methode contains() für Polygone.[80](Ob ein Punkt im Polygon ist, entscheidet der Gerade/Ungerade-Test (http://en.wikipedia.org/wiki/Point_in_polygon).) Sie arbeitet aber nur korrekt für Punkte innerhalb der eingeschlossenen Fläche. Bei Abfrage von Punkten, die den Eckpunkten entsprechen, kommen immer sehr willkürliche Werte heraus – und genauso bei der Abfrage, ob die Punkte auf der Linie zum Innenraum gehören oder nicht.

Die Klasse Point2D berechnet den Abstand zweier Punkte mit den Methoden:

  • double distance(double PX, double PY)
  • static double distance(double X1, double Y1, double X2, double Y2)
  • double distance(Point2D pt)
  • double distanceSq(double PX, double PY)
  • static double distanceSq(double X1, double Y1, double X2, double Y2)
  • double distanceSq(Point2D pt)

Verwandte Methoden zur Berechnung des Abstands eines Punktes zur Line bietet auch Line2D:

  • double ptLineDist(double PX, double PY)
  • static double ptLineDist(double X1, double Y1, double X2, double Y2, double PX, double PY)
  • double ptLineDist(Point2D pt)
  • double ptLineDistSq(double PX, double PY)
  • static double ptLineDistSq(double X1, double Y1, double X2, double Y2, double PX, double PY)
  • double ptLineDistSq(Point2D pt)
  • double ptSegDist(double PX, double PY)
  • static double ptSegDist(double X1, double Y1, double X2, double Y2, double PX, double PY)
  • double ptSegDist(Point2D pt)
  • double ptSegDistSq(double PX, double PY)
  • static double ptSegDistSq(double X1, double Y1, double X2, double Y2, double PX, double PY)
  • double ptSegDistSq(Point2D pt)

Die relativeCCW()-Methoden von Line2D können herausfinden, ob der Punkt rechts oder links einer Linie liegt. Ob sich zwei Linien schneiden, ermitteln zwei überladene Line2D-Methoden intersectsLine(). Neben der Objektmethode testet die mit acht Parametern gesegnete statische Methode linesIntersect(), ob zwei Liniensegmente sich schneiden. Zwei allgemeine intersects()-Methoden deklariert die Schnittstelle Shape, doch bei diesen Methoden aus Line2D geht es darum, ob eine Form ein Rechteck schneidet. intersectsLine() bietet auch Rectangle2D und meldet damit, ob ein Rechteck eine Linie schneidet.

Genau das Gegenteil vom Schnitt ist die Vereinigung. So legt die Methode union() von Rectangle2D zwei Rechtecke zusammen, wobei ein neues Rechteck entsteht, das die äußersten Koordinaten der beiden Ursprungsrechtecke besitzt. Die Methode outcode() ist ebenfalls interessant, da sie über eine Bit-Maske in der Rückgabe angibt, wo ein außerhalb des Rechtecks befindlicher Punkt steht, also etwa OUT_BOTTOM, OUT_LEFT, OUT_RIGHT, OUT_TOP.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.







<< zurück
  Zum Katalog
Zum Katalog: Java 7 – Mehr als eine Insel
Java 7 – Mehr als eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Einstieg in Eclipse 3.7






 Einstieg in
 Eclipse 3.7


Zum Katalog: Android 3






 Android 3


Zum Katalog: NetBeans Platform 7






 NetBeans Platform 7


Zum Katalog: Java ist auch eine Insel






 Java ist
 auch eine Insel


Zum Katalog: Apps entwickeln für Android 4






 Apps entwickeln
 für Android 4


Zum Katalog: Java 7






 Java 7


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2012
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de