In den bisherigen Beispielprogrammen sind uns schon des öfteren die Routinen
Graphics2D.fill(Shape s) und Graphics2D.draw(Shape s)
begegnet. Die Operationen, die man mit diesen Methoden ausführt, heißen
Painting und Stroking. Sie werden - besonders das Stroking - in diesem
Kapitel behandelt.
Als Painting bezeichnet man das Füllen eines Umrisses (Shape-Objekt)
mit einer Farbe (Paint-Objekt). Umrisse werden
in einem Graphics2D-Objekt mit der Methode fill(Shape s) gefüllt. Die aktuelle
Füllfarbe wird vorher mit setPaint(Paint p) gesetzt.
Es kann sich hierbei um ein beliebiges Objekt handeln, welches das Paint-Interface implementiert.
Als Stroking bezeichnet man das Zeichen der Umrißlinie eines Shape-Objektes.
Das Zeichnen der Umrißlinie erfolgt anhand eines Stroke-Objektes. Stroke ist
ein Interface, daß Methoden vorschreibt, die ein konkreter Pinselstrich implementieren muß.
Das Zeichnen von Umrissen geschieht mit der Graphics2D-Methode draw(Shape s).
Es wird der durch die Methode setStroke(Stroke s) gesetzte Pinselstrich verwendet.
Als Farbe kommt auch hier die durch setPaint(Paint p) gesetzte Farbe zur Verwendung.
Das Stroke-Interface definiert abstrakt einen Pinselstrich. Es schreibt lediglich eine Methode
vor:
public Shape createStrokedShape(Shape s).
Die Funktionsweise ist einfach nachzuvollziehen: Wenn die Umrißlinie eines Shape-Objektes
gezeichnet werden soll, dann wird dieses Shape-Objekt von Graphics2D
an createStrokedShape(Shape s) übergeben. Graphics2D erhält als Ergebnis ein Shape-Objekt,
daß den Umriß mit fertig gezeichneter Umrißlinie darstellt.
Wenn z.B. ein Rechteck mit einer gestrichelten Umrißlinie gezeichnet werden soll, so wird
das Rechteck von Graphics2D an die createStrokedShape(...)-Methode der
jeweiligen Stroke-Implemenation übergeben. Diese wird dann ein Shape-Objekt zurückliefern,
dessen Umrißlinie in diesem Fall aus abwechselnd sichtbaren und unsichtbaren Liniensegmenten besteht -
einer gestrichelten Linie. createStrokedShape(...) könnte z.B. auch dafür sorgen, daß
die Umrißlinie mit einer Dicke von 5 Pixeln gezeichnet wird oder daß der Umriß aus lauter
Dreiecken besteht.
Die Klasse java.awt.BasicStroke ist eine konkrete Stroke-Implementation.
Sie bietet folgende Funktionalität an:
BasicStroke hat folgende Konstruktoren:
| Konstruktor | Beschreibung |
|---|---|
BasicStroke() |
konstruiert einen BasicStroke mit Default-Attributen |
BasicStroke(float width) |
konstruiert einen Default-BasicStroke mit der Breite width |
BasicStroke(float width, int cap, int join) |
konstruiert einen BasicStroke der Breite width,
dem End Style cap und dem Join Style join.
Die Styles werden durch in der Klasse definierte Konstanten angegeben,
(s. folgendes Programmbeispiel)
|
BasicStroke(float width, int cap, int join, float joinlimit) |
konstruiert einen BasicStroke der Breite width,
dem End Style cap, dem Join Style join
und einem Limit joinlimit in Pixeln für den angegeben
Join Style.
Die Styles werden durch in der Klasse definierte Konstanten angegeben,
(s. folgendes Programmbeispiel)
|
BasicStroke(float width, int cap, int join, float joinlimit, float[] dash, float dash_phase) |
wie vorheriger Konstruktor, aber mit einem Array dash, welches
das Muster (in Pixeleinheiten) für die Strichelung enthält (s. Beispiel).
dash_phase gibt an, daß bei der ersten Verwendung (und nur hier) von
dash vom ersten Array-Wert dash_phase Pixel subtrahiert
wird.
|
Die Verwendung von BasicStroke möchte ich anhand eines Beispieles aufzeigen. Hier werden
die Verschiedenen Join Styles anhand eines V-Förmigen GeneralPath-Pfades demonstriert. Des
weiteren wird ein Rechteck mit der Strichelung "30 Pixel sichtbar, 10 Pixel unsichtbar,
5 Pixel sichtbar, 10 Pixel unsichtbar" gezeichnet. Als Zeichenfarbe kommt ein zyklischer
Farbverlauf von gelb nach lila zum Einsatz.
(Zugriff auf die Quelle):
public void paint(Graphics g) {
//Upcast --> mehr Funktionen in Graphics2D
Graphics2D g2d=(Graphics2D)g;
g2d.setPaint( new GradientPaint(20,50,new Color(255,241,9),
60,50,new Color(188,9,255),
true /*zyklischer Verlauf*/ )
);
//V-förmigen Shape erstellen:
GeneralPath vshape = new GeneralPath();
vshape.moveTo( 20, 50 );
vshape.lineTo( 50, 200 );
vshape.lineTo( 80, 50 );
//Pinselstriche mit allen möglichen Join- und Endstyles:
BasicStroke s1=new BasicStroke( 15, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL );
BasicStroke s2=new BasicStroke( 15, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_MITER );
BasicStroke s3=new BasicStroke( 15, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_ROUND );
//wiederholt:
// Pinselstrich setzen,Malen,Koordinatentranslation,...
g2d.setStroke(s1);
g2d.draw(vshape);
g2d.translate( 100, 0 );
g2d.setStroke(s2);
g2d.draw(vshape);
g2d.translate( 100, 0 );
g2d.setStroke(s3);
g2d.draw(vshape);
//Translation aufheben
g2d.setTransform( new AffineTransform() );
//---------------------------------------------------------
//Rechteck mit runden Ecken erzeugen
RoundRectangle2D dashedRect =
new RoundRectangle2D.Double( 20,250,500,200,40,40 );
float[] dash_array=new float[4];
dash_array[0]=30; //sichtbar
dash_array[1]=10; //unsichtbar
dash_array[2]=5; //sichtbar
dash_array[3]=10; //unsichtbar
BasicStroke s4 = new BasicStroke(
5f, //Breite
BasicStroke.CAP_SQUARE, //End Style
BasicStroke.JOIN_ROUND, //Join Style
1f, //Limit für Join
dash_array, //Strichelung
0 //offset in Pixeln f. Strichelung
);
g2d.setStroke( s4 ); //gestrichelter Pinselstrich setzen
g2d.draw( dashedRect ); //gestricheltes Rechteck malen
}
Das Ergebnis sieht wie folgt aus (mit Beschriftung):
