14.9 Clipping-Operationen
Alle primitiven Zeichenoperationen wirken sich auf den gesamten Bildschirm aus und sind nicht auf bestimmte Bereiche eingeschränkt. Wenn wir Letzteres erreichen wollen, setzen wir einen so genannten Clipping-Bereich, außerhalb dessen nicht mehr gezeichnet wird. Leider war in der Vergangenheit die Implementierung dieses Clippings immer fehleranfällig, so dass eine falsche Zeichnung durchaus vorkommen konnte. Wer da auf Nummer sicher gehen will, sollte ein Offscreen-Bild anlegen, Operationen auf diesem Image machen und dann das Bild zeichnen. Doch bleiben wir beim herkömmlichen Clipping. Dies ist eine Eigenschaft des aktuellen Graphic-Objekts. Mit der Methode clipRect(int x, int y, int width, int height) lässt sich dieser Bereich einschränken. Dann erfolgen alle Operationen in diesem Bereich. Das folgende Programm erzeugt zwei Clipping-Bereiche und füllt einen sehr großen Bereich aus, der aber nicht sichtbar ist:
Listing 14.10 ClipDemo.java
import java.awt.*;
public class ClipDemo extends Frame
{
public void paint( Graphics g )
{
Graphics gcopy = g.create();
// Clipping auf
g.clipRect( 100, 100, 100, 100 );
g.setColor( Color.orange );
g.fillRect( 0, 0, 500, 500 );
g.setColor( Color.black );
g.drawOval( 150, 100, 100, 100 );
// Zweiter Clipping-Bereich
g.clipRect( 250, 250, 50, 50 );
g.setColor( Color.blue );
g.fillRect( 0, 0, 5000, 5000 );
// Die ursprüngliche Größe zurücksetzen
gcopy.setColor( Color.yellow );
gcopy.fillRect( 50, 50, 20, 50 );
gcopy.dispose();
}
public static void main( String args[] )
{
ClipDemo cd = new ClipDemo();
cd.setSize( 400, 400 );
cd.show();
}
}
Hier klicken, um das Bild zu Vergrößern
Abbildung 14.3 Clipping-Bereiche
Den alten Zustand für Graphics wiederherstellen
Für die Zeichenoperationen im Clipping-Bereich gibt es noch eine alternative Implementierung. Diese verzichtet auf die Kopie des Grafikkontexts mittels create() am Anfang und setzt am Schluss vor die Stelle von gcopy ein getGraphics(), mit dem sich der alte Kontext wiederherstellen lässt. Dann können wir wieder mit g.drawXXX() arbeiten, und gcopy ist überflüssig. Mit dem Original können wir dann das Clipping zurücksetzen und wieder ohne Zuschnitt arbeiten. Wenn wir nach dem Clipping das Original nicht mehr benötigen, können wir selbstverständlich auf die Kopie verzichten.
Alternative Formen
Durch setClip() können alternativ zu den rechteckigen Formen auch beliebige Shape-Objekte die Clipping-Form vorgeben. Nachfolgende paint()-Methode benutzt als Beschnitt ein Dreieck:
Listing 14.11 ClipDemo.java
import java.awt.*;
public class ClipDemo extends Frame
{
public void paint( Graphics g )
{
Rectangle r = g.getClipBounds();
System.out.println( r );
Polygon p = new Polygon(
new int[]{200,100,300},
new int[]{100,300,300}, 3
);
g.setClip( p );
g.setColor( Color.orange );
g.fillRect( 0, 0, 500, 500 );
}
public static void main( String args[] )
{
ClipDemo cd = new ClipDemo();
cd.setSize( 400, 400 );
cd.show();
}
}
Bei alten Implementierungen funktioniert dies nicht. Auf der Konsole erscheint dann eine Fehlermeldung der folgenden Art:
java.lang.IllegalArgumentException:\ setClip(Shape) only supports Rectangle objects
Verdeckte Bereiche und schnelles Bildschirmerneuern
Clipping-Bereiche sind nicht nur zum Einschränken der Primitiv-Operationen sinnvoll. Bei Bereichsüberdeckungen in Fenstern liefern sie wertvolle Informationen über den neu zu zeichnenden Bereich. Bei einer guten Applikation wird nur der Teil wirklich neu gezeichnet, der auch überdeckt wurde. So lässt sich Rechenzeit sparen.
Beispiel Informationen über Clipping-Bereiche
public void paint( Graphics g )
{
Rectangle r = g.getClipBounds();
System.out.println( r );
}
Das Programm erzeugt etwa
java.awt.Rectangle[x=4,y=23,width=392,height=373]
|
java.awt.Rectangle[x=104,y=87,width=292,height=309]
java.awt.Rectangle[x=104,y=87,width=286,height=211]
java.awt.Rectangle[x=104,y=87,width=243,height=196]
java.awt.Rectangle[x=104,y=87,width=221,height=219]
java.awt.Rectangle[x=101,y=89,width=221,height=219]
...
|
Hieraus lassen sich verschiedene Fensteroperationen ableiten. Ich habe ein fremdes Fenster über das Java-Fenster geschoben und dann das fremde Fenster verkleinert. Die Rectangle-Informationen geben Aufschluss über die Größe der neu zu zeichnenden Bereiche. Haben wir schon daran gedacht, die Information in einem Image-Objekt abzulegen, lässt sich wunderbar drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) nutzen. Hier müssen wir die Werte aus dem Rectangle auslesen und in drawImage() übertragen. getClipBounds() liefert ein Rectangle-Objekt, dessen Werte für drawImage() nötig sind. Da jedoch auch beliebige Formen möglich sind, liefert getClip() ein Shape-Objekt. getClipRect() ist die veraltete Methode zu getClipBounds(), sonst aber identisch. Die Methode getClipBounds(Rectangle) - eine der wenigen nicht abstrakten Methoden in Graphics - legt die Informationen im übergebenen Rectangle-Objekt ab, welches auch zurückgeliefert wird. Sie ruft nur getClipBounds() auf und überträgt die vier Attribute in das Rechteck.
|