Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Download: - ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /Java-Insel | vor >>
Java ist auch eine Insel von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel 7., aktualisierte Auflage geb., mit DVD (November 2007) 1.492 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1146-8 |
| 16 Grafikprogrammierung
|  | 16.1 Grundlegendes zum Zeichnen
|  |  | 16.1.1 Die paint()-Methode für das AWT-Frame
|  |  | 16.1.2 Zeichen von Inhalten mit JFrame
|  |  | 16.1.3 Auffordern zum Neuzeichnen mit repaint()
|  |  | 16.1.4 Grundbegriffe: Koordinaten, Punkte, Pixel
|  |  | 16.1.5 Die ereignisorientierte Programmierung ändert Fensterinhalte
|  |  | 16.1.6 Java 2D-API
|  | 16.2 Einfache Zeichenfunktionen
|  |  | 16.2.1 Linien
|  |  | 16.2.2 Rechtecke
|  |  | 16.2.3 Ovale und Kreisbögen
|  |  | 16.2.4 Polygone und Polylines
|  | 16.3 Zeichenketten schreiben und Fonts
|  |  | 16.3.1 Zeichenfolgen schreiben
|  |  | 16.3.2 Die Font-Klasse
|  |  | 16.3.3 Einen neuen Font aus einem gegebenen Font ableiten
|  |  | 16.3.4 Zeichensätze des Systems ermitteln
|  |  | 16.3.5 Neue TrueType-Fonts in Java nutzen
|  |  | 16.3.6 Font-Metadaten durch FontMetrics
|  | 16.4 Geometrische Objekte
|  |  | 16.4.1 Die Schnittstelle Shape
|  |  | 16.4.2 Kreisförmiges
|  |  | 16.4.3 Kurviges
|  |  | 16.4.4 Area und die konstruktive Flächengeometrie
|  |  | 16.4.5 Pfade
|  |  | 16.4.6 Punkt in Form, Schnitt von Linien, Abstand Punkt/Linie und Weiteres
|  | 16.5 Das Innere und Äußere einer Form
|  |  | 16.5.1 Farben und die Paint-Schnittstelle
|  |  | 16.5.2 Farben mit der Klasse Color
|  |  | 16.5.3 Die Farben des Systems über SystemColor
|  |  | 16.5.4 Composite und Xor
|  |  | 16.5.5 Dicke und Art der Linien von Formen bestimmen über Stroke
|  | 16.6 Bilder
|  |  | 16.6.1 Eine Übersicht über die Bilder-Bibliotheken
|  |  | 16.6.2 Bilder mit ImageIO lesen
|  |  | 16.6.3 Ein Bild zeichnen
|  |  | 16.6.4 Programm-Icon/Fenster-Icon setzen
|  |  | 16.6.5 Splash-Screen
|  |  | 16.6.6 Bilder im Speicher erzeugen
|  |  | 16.6.7 Pixel für Pixel auslesen und schreiben
|  |  | 16.6.8 Bilder skalieren
|  |  | 16.6.9 Schreiben mit ImageIO
|  |  | 16.6.10 Asynchrones Laden mit getImage() und dem MediaTracker
|  |  | 16.6.11 Selbst definierte Cursor
|  |  | 16.6.12 VolatileImage
|  | 16.7 Weitere Eigenschaften von Graphics
|  |  | 16.7.1 Eine Kopie von Graphics erstellen
|  |  | 16.7.2 Koordinatensystem verschieben
|  |  | 16.7.3 Beschnitt (Clipping)
|  | 16.8 Zeichenhinweise durch RenderingHints
|  | 16.9 Transformationen mit einem AffineTransform-Objekt
|  | 16.10 Drucken
|  |  | 16.10.1 Drucken der Inhalte
|  |  | 16.10.2 Bekannte Drucker
|  | 16.11 Grafikverarbeitung ohne grafische Oberfläche
|  |  | 16.11.1 Xvfb-Server
|  |  | 16.11.2 Pure Java AWT Toolkit (PJA)
|  | 16.12 Zum Weiterlesen
## 16.4 Geometrische 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: einmal, indem wir Objekte aufbauen und diese dann zeichnen lassen, oder über die speziellen Zeichenfunktionen von Graphics wie die bekannten Methoden drawLine(), drawRect(). Objekte bieten den Vorteil, dass sie sich in einer Datenstruktur sammeln lassen. Beginnen wir mit einem Programm, das eine Linie als Form-Objekt zeichnet: Listing 16.7 com/tutego/insel/ui/g2d/First2Ddemo.java
    package com.tutego.insel.ui.g2d;

    import java.awt.*;
    import java.awt.geom.Line2D;
    import javax.swing.*;

    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, 70 ) );
      }
      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 weich gezeichnet ist, wir dies aber wünschen, setzen wir einen setRenderingHint(). Die Argumente und die Funktionen werden später näher beschrieben. Hier klicken, um das Bild zu vergrößern Abbildung 16.2 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. ### 16.4.1 Die Schnittstelle Shape 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 implementierten die äußere Klasse mit den Genauigkeiten float und double. Ein Beispiel für Line2D haben wir im oberen Programm schon aufgeführt; die öffentliche konkrete innere Klasse mit der Genauigkeit double heißt Line2D.Double. Hier klicken, um das Bild zu vergrößern 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 Rechteck verändern und abfragen. Unter anderem gibt es Methoden, die abfragen, ob sich ein Punkt im Rechteck befindet (contains() aus der Schnittstelle Shape), wie die Ausmaße sind oder wo das Rechteck seine Mitte besitzt.
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.
### 16.4.2 Kreisförmiges Die Klasse java.awt.geom.Arc2D kümmert sich um Kreisbögen. Diese Bögen werden wie bei drawArc() in einem 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. Listing 16.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 );
    }
### 16.4.3 Kurviges Die Klasse QuadCurve2D beschreibt quadratische Kurvensegmente. Dies sind Kurven, die durch zwei Endpunkte und durch dazwischen liegende Kontrollpunkte gegeben sind. CubicCurve2D beschreibt kubische Kurvensegmente, die durch zwei Endpunkte und zwei Kontrollpunkte definiert ist. Kubische Kurvensegmente werden auch Bézier-Kurven genannt. ### 16.4.4 Area und die konstruktive Flächengeometrie 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, sehen. Die wichtigsten Funktionen 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 ) Vereinigt die aktuelle Form mit rhs. void subtract( Area rhs ) Zieht von der aktuellen Form die Form rhs ab. Weitere Funktionen 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. ### 16.4.5 Pfade Ein Pfad besteht aus zusammengesetzten Segmenten, die dann 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 );
    }
Hier klicken, um das Bild zu vergrößern 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 die 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 zwei Rechtecke: ein blaues mit GeneralPath. WIND_NON_ZERO und ein anderes, rotes 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 unendlich viele Schnittpunkte. Diese Regel wird aber nur dann wichtig, wenn wir mit nichtkonvexen Formen arbeiten. Solange sich die Linien nicht schneiden, ist dies kein Problem. Listing 16.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 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 16.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. Hier klicken, um das Bild zu vergrößern Abbildung 16.3 Die Windungsregeln WIND_NO_ZERO und WIND_EVEN_ODD ### 16.4.6 Punkt in Form, Schnitt von Linien, Abstand Punkt/Linie und Weiteres Die unterschiedlichen Klassen für die geometrischen Formen besitzen Funktionen, 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. [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 Anfrage, ob die Punkte auf der Linie zum Innenraum gehören oder nicht. Die Klasse Point2D berechnet den Abstand zweier Punkte mit den Funktionen distance() und distanceSq(). Eine verwandte Funktion bietet auch Line2D mit ptLineDist() bzw. ptLineDistSq(), was den Abstand eines Punktes zur Line berechnet. Die relativeCCW()-Funktionen können herausfinden, ob der Punkt rechts oder links einer Linie liegt. Ob sich zwei Linien schneiden, ermitteln die Line2D-Funktionen intersectsLine(). Die Methoden sind Objektfunktionen, und zur Verwirrung testet die mit 8 Parametern gesegnete statische Funktion linesIntersect(), ob zwei Liniensegmente sich schneiden. Zwei allgemeine intersects()-Funktionen definiert die Schnittstelle Shape, doch bei diesen Funktionen 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, welches 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.
Name |
E-Mail |
Ihr Kommentar |
<< zurück | <top> | vor >>

Copyright © Galileo Press 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> 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