ダブルバッファリング


Swing のちらつき防止

AWT のコンポーネントにおいて、アニメーションなどを行うと
再描画する度にコンポーネント全体を背景色でクリアするためちらつく現象がありました
このちらつきを防止する最良の手段として、私たちはダブルバッファリングを使ったはずです

Swing では、デフォルトで高度にこのちらつき防止とダブルバッファリングがサポートされています
コンポーネントは描画する度に背景色でクリアするという仕様は AWT のままですが
ルートコンテナがダブルバッファリングで描画するためちらつきません

Swing の JComponent クラスには、ダブルバッファリングを行うための
setDoubleBuffered() メソッドがサポートされています

public void setDoubleBuffered(boolean aFlag)

aFlag に true を指定すると、このコンポーネントの描画処理は
すべてオフスクリーンに描画し、それを画面にコピーするダブルバッファリング方式を使用します
コンポーネントがバッファを使用しているか否かは isDoubleBuffered() を使います

public boolean isDoubleBuffered()

このメソッドは、コンポーネントがバッファを使用して描画する場合は true を返します

デフォルトで、JComponent はバッファリングをしません
最終的な描画を行うのはルートコンテナであり、バッファを利用した描画はコンテナだけで良いのです
逆に言えば、コンポーネントにダブルバッファリングの意味はないのです

このような理由から Swing では JRootPane とそのコンテンツペイン
それから JPanel クラスがダブルバッファリングを有効にしています
これは、一般にルートコンテナとなるのは JPanel またはコンテンツペインだからです

JApplet や JFrame でダブルバッファリングの実装を直接操作するには
コンテンツペインのほかに JRootPane コンポーネントを取得する必要があります
そのためには getRootPane() メソッドを使用します

public JRootPane getRootPane()

このメソッドは RootPaneContainer インターフェイスで宣言されているので
ルートペインを実装しているコンテナはこのメソッドをサポートしています
JRootPane の詳細は後記しますが、このクラスは JComponent を継承しています

コンテンツペインは getContentPane() で取得できますが、型は Container クラスです
しかし、JRootPane のコンテンツペインならば実体は JComponent なので
JComponent 型にキャストして setDoubleBuffered() にアクセスできます
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test extends JApplet implements ItemListener {
	public void init() {
		Container contentPane = getContentPane();
		contentPane.setLayout(new FlowLayout());

		JComponent jcom = new JComponentEx();
		jcom.setPreferredSize(new Dimension(200 , 50));
		contentPane.add(jcom);
		((Checkbox)contentPane.add(
			new Checkbox("ダブルバッファリング" , true))).addItemListener(this);
	}
	public void itemStateChanged(ItemEvent e) {
		Checkbox ch = (Checkbox)e.getItemSelectable();
		getRootPane().setDoubleBuffered(ch.getState());
		((JComponent)getContentPane()).setDoubleBuffered(ch.getState());
	}
	class JComponentEx extends JComponent implements Runnable {
		int x = 0;
		public JComponentEx() {
			(new Thread(this)).start();
		}
		public void run() {
			while(true) {
				Dimension dim = getSize();
				if (++x == (dim.width - 10)) x = 0;
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						repaint();
					}
				});
				try {	Thread.sleep(10);	}
				catch(Exception err) {}
			}
		}

		public void paintComponent(Graphics g) {
			g.setColor(Color.blue);
			g.fillRect(10 , 10 , 10 + x , 20);
		}
	}
}


このプログラムは、ブルーの横棒が右に向かって伸びていくプログラムです
ダブルバッファリングのチェックボタンを外すと
ルートペイン、及びコンテンツペインのバッファを使った描画が解除されます

バッファを使っているデフォルトの状態では、ちらつきは発生しません
AWT では、独自にダブルバッファリングを行う必要がありましたが
Swing ではルートペインとコンテンツペインがこれを行うため、デフォルトでちらつきません
チェックを外すと、これら二つのバッファによる描画が解除されるため、描画処理にちらつきが発生します




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