クリップ


レンタリングの範囲

Graphicsには、クリップという短形が関連付けられています
クリップと言っても、プロモーションビデオのクリップ集を作ろうという話じゃございません
(イエローモンキは、かっこよいですよぉ〜♪)

クリップはJavaのグラフィックスを理解するうえで重要な機能であり
高度なダブルバッファリングやアニメーションでは欠かせない技術です

クリップは、paint()メソッドが描画するレンタリング領域です
たとえば、ある一定の領域しか変更しないのに、コンポーネント全体を再描画するのは
非常に効率の悪い方法としか言えません

クリップを指定すれば、レンタリングはクリップの範囲だけで行われます
通常は長方形しか選択できませんでしたが、Java2Dの導入で任意の形状をクリップにできます

現在のクリップ範囲を得るには、GraphicsクラスのgetClip()メソッドか
getClipBounds()メソッドを使用します

public abstract Shape getClip()
public abstract Rectangle getClipBounds()

getClip()メソッドは、現在の領域を表すShapeオブジェクトを返します
これはjava.awt.Shapeインターフェイスのオブジェクトです
このインターフェイスはRectangleクラスとPolygonクラスがインプリメントしています

しかし、Shapeオブジェクトは全てのクリップ操作で保証されるわけではありません
この戻り値が保証されるのは、後で説明するsetClip()に渡すときだけです

Javaのコンポーネントの再描画は、すでにご存知だと思いますが
repaint()のときだけではなく、一度コンポーネントが隠され
再び表示される時に、paint()メソッドは実行されます

このとき、レンタリングされるのはクリップ領域だけです
もちろん、実際にはアプレット全体が再描画されているのですが
表示が崩れた部分がクリップされているので、結果としてクリップ領域が連続して表示されます
import java.applet.Applet;
import java.awt.*;

/*	<applet code="test.class" width="300"height="300">
 	</applet>
*/

public class test extends Applet {
	public void init() {
		setBackground(Color.white);
	}
	public void paint(Graphics g) {
		Dimension dim = getSize();
		Rectangle rct = g.getClipBounds();
		g.setColor(Color.red);
		g.fillRect(0 , 0 , dim.width , dim.height);
		System.out.println("x = " + rct.x + " : y = " + rct.y +
			" : w = " + rct.width + " : h = " + rct.height );		
	}
}
このプログラムをアプレットビューワで実行してください
アプレットを、別のウィンドウなどで隠し、再びウィンドウを離すと
表示が崩れた部分をレンタリングします

このときのクリップの範囲がコンソールに出力されます
崩れた部分のみがクリップされているのがわかると思います

クリップの範囲を設定するにはsetClip()メソッド゙を使用します

public abstract void setClip( int x, int y, int width, int height )
public abstract void setClip( Shape clip )

x , yはクリップの左上となるx座標とy座標
widthとheightは横と縦の幅を指定します(つまり、長方形を選択)

clipには、クリップの領域を表すShapeオブジェクトを指定しますが
この結果が保証されるのはgetClip()メソッドの戻り値かRectangleオブジェクトのみです
それ以外は保証されないので、プログラマの責任範囲です

次のプログラムは、星型(?)にクリップした領域に画像を表示させています
ただし、長方形以外のクリップは新しいJavaです (Java 2D)
実行される環境を、多少考慮する必要があるかもしれません (2001年3月 現在)
import java.applet.Applet;
import java.awt.*;

/*	<applet code="test.class" width="300"height="300">
 	</applet>
*/

public class test extends Applet {
	Image img;
	public void init() {
		setBackground(Color.black);
	}
	public void paint(Graphics g) {
		int x[] = { 10 , 90 , 150 , 210 , 290 , 210 , 290 , 150 , 10 , 90 };
		int y[] = { 150 , 130 , 10 , 130 , 150 , 170 , 290 , 200 , 290 , 170};
		img = getImage(getDocumentBase() , "img/test.jpg");
		g.setClip(new Polygon(x , y , 10));
		g.drawImage(img , 0 , 0 , 300 , 300 , this);
	}
}
多角形のクリップ領域に画像が表示されます

また、クリップの内部にさらにクリップすることもできます
つまり、指定された長方形のうちで現在のクリップ領域だけをクリップする形になります
これにはclipRect()メソッドを用います

public abstract void clipRect( int x, int y, int width, int height )

パラメータには、x座標y座標からの長方形を指定します
widthは横幅、heightは縦幅です

このメソッドの長方形と、クリップ領域の交差部分が新しいクリップ領域になります
現在のクリップ領域より小さくするために用いられます
import java.applet.Applet;
import java.awt.*;

/*	<applet code="App48.class" width="300"height="300">
	<param name="img" value="img/test.jpg">
 	</applet>
*/

public class App48 extends Applet {
	Image img;
	public void init() {
		setBackground(Color.white);
	}
	public void paint(Graphics g) {
		img = getImage(getDocumentBase() , getParameter("img"));
		g.setColor(Color.black);

		g.drawRect(50 , 50 , 200 , 200);
		g.drawRect(10 , 10 , 140 , 140);

		g.setClip(50 , 50 , 200 , 200);
		g.clipRect(10 , 10 , 140 , 140);

		g.drawImage(img , 0 , 0 , 300 , 300 , this);
	}
}
アプレット

setClip()の領域と、clipRect()の指定領域の交差面がクリップとなります
drawRect()は、交差する領域がわかりやすいように
クリップ領域とclipRect()の領域と同じ長方形を描いています



前のページへ戻る次のページへ