ダブルバッファリング
イメージの生成
さて、ここでダブルバッファリングの基本的概念と扱いに触れましょう
ダブルバッファリングとは、早い話が画像更新のちらつきを回避する技術だと思ってください
以前、コンポーネントを更新しつづけることで簡単なアニメーションを表現しました
しかし、そのときは更新するたびに画面がちらついていましたね
これでは自分のWebページがピカチ○ウ現象に陥りかねません
画面がちらつくのは、コンポーネント更新時に一度背景色で塗りつぶすためです
この現象はupdate()メソッドをオーバーライドすることで回避できますが、まだ問題があります
画面に何かを付け足していくようなプログラムの場合は、これで解決することができますが
画面の一部を動的に更新する場合、この方法だけでは実現できません
そこでダブルバッファリングが用いられます
ダブルバッファリングの基本概念は、イメージの生成です
まずオフスクリーンと呼ばれる、見えないウィンドウを作ります
プログラムはこの見えないウィンドウを更新します
最後に、オフスクリーンをコンポーネントにdrawImage()で描画することで
画面のクリアからイメージ操作の全ての過程をウィンドウに映すことなく
全ての作業を終えてから表示することで、ちらつきを防止することができるのです
まず、オフスクリーンとなるバッファを生成します
これはComponentクラスのcreateImage()メソッドを使用します
public Image createImage( ImageProducer producer )
public Image createImage( int width, int height )
ImageProducerを渡すcreateImageはダブルバッファリングでは用いません
今回使用するのは下のcreateImageの書式です
widthとheightはオフスクリーンとなるバッファのサイズを指定します
ただし、このオフスクリーンを操作するにはグラフィックコンテキストが必要です
drawRect()やfillOval()など、グラフィックを担当するのはGraphicsクラスでしたね
グラフィックコンテキストを得るにはImageクラスのgetGraphics()メソッドを使用します
public abstract Graphics getGraphics()
オフスクリーン イメージに描画するためのグラフィックス コンテキストを作成します
getGraphics()が返したコンテキストが操作の対象になります
全ての作業はバッファで行われ、最後にバッファをウィンドウにコピーします
import java.applet.Applet;
import java.awt.*;
/* <applet code="App21.class" width="600"height="300">
</applet>
*/
public class App21 extends Applet {
Image buf;
Graphics ct;
Dimension dim;
public void init() {
dim = getSize();
buf = createImage(dim.width , dim.height);
}
public void paint(Graphics g) {
ct = buf.getGraphics();
ct.setColor(Color.white);
ct.fillRect(0 , 0 , dim.width , dim.height);
ct.setColor(Color.red);
ct.fillRect((dim.width / 2) - 50 , (dim.height / 2) - 50 , 100 , 100);
g.drawImage(buf , 0 , 0 ,this);
}
}
このプログラムは動的にアニメーションしないので、あまり意味は感じませんが
内部動作は普段と大きく違います
まず buf = createImage(dim.width , dim.height); で
bufにダブルバッファリングで使用できる、オフスクリーンで描画可能なイメージを作成します
次に、生成されたイメージ(オフスクリーン)のグラフィカルコンテキストを ct = buf.getGraphics(); で生成します
ここで生成したグラフィカルコンテキストを操作することで、オフスクリーンのイメージを描画できます
最後に g.drawImage(buf , 0 , 0 ,this); でイメージをコンポーネントにコピーしています
これがダブルバッファリングです
この技法を用いれば、アニメーションで画面がちらつくことがありません
Javaアプレットでゲームなどを作る時は、重要な画面操作の一つです
import java.applet.Applet;
import java.awt.*;
/* <applet code="App22.class" width="300"height="300">
</applet>
*/
public class App22 extends Applet implements Runnable {
boolean chkx = true , chky = true;
int x = 250 , y = 140;
Thread th;
Image buf;
Graphics ct;
Dimension dim;
public void init() {
th = new Thread(this);
th.start();
dim = getSize();
buf = createImage(dim.width , dim.height);
}
public void run() {
try {
while(true) {
if (chkx) x++;
else x--;
if (chky) y++;
else y--;
if (x == (dim.width - 20)) chkx = false;
if (x == 0) chkx = true;
if (y == (dim.height - 20)) chky = false;
if (y == 0) chky = true;
repaint();
Thread.sleep(10);
}
}
catch (InterruptedException err) { }
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
if (ct == null) ct = buf.getGraphics();
ct.setColor(Color.white);
ct.fillRect(0 , 0 , dim.width , dim.height);
ct.setColor(Color.red);
ct.fillRect(x , y , 20 , 20);
g.drawImage(buf , 0 , 0 ,this);
}
}
一見プログラムは長ったらしいですが
それは、宣言部や制御部分(アルゴリズム)であり、バッファリングの重要な部分は極一部です
このプログラムはまだ汎用的とは言えませんが、改良すれば面白いものが作れるかもしれません
アプレットやアプリケーションの開発にアニメーションは欠かせません
アニメーションはソフトウェアの演出やレイアウトに大きく影響します