自動ダブルバッファリング



 paintComponent( )でググるとこんなページがトップでHIT。
16.2 Swing コンポーネントの描画
慶応義塾学情報処理教育室の講座のサイト18年度版より)

【例2】
マウスでクリックした場所に円を書いてみましょう。

【図省略】

ソース・プログラム Graph8.java

 これは!以前ベースにしたサンプルに良く似た動作じゃないか!それをswingで書いてあるのか!
 昨日の紹介文のように、paintComponent( )の親メソッド(super)を呼び出してるし、これは本物のswing技術のようだ。


import java.awt.event.* ;
import javax.swing.* ;
import java.awt.Graphics ;
import java.awt.Color ;

public class Graph8 extends JPanel implements MouseListener {
int x = -1; // 中心のx座標
int y = -1; // 中心のy座標
int r = 30; // 円の半径
final static Color bc = Color.white; // 背景色
final static Color dc = Color.green; // 描画色

public Graph8() {
addMouseListener(this);
setBackground(bc);
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
if(x>=0) {
g.setColor(dc);
g.drawOval(x-r, y-r, 2*r, 2*r);
}
}

public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}

public void mouseReleased(MouseEvent e) { }
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
frame.getContentPane().add( new Graph8() );
frame.setSize(200, 200);
frame.setVisible(true);
}
}

※勝手に転載しています。


 しかし、ウインドウを閉じるときの終了動作を記述する部分がAWTのままなのが気になる。
 swingにもちゃんと
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
(「本格Java入門:佐々木整:技術評論社」に載っていた。)
という簡単かつswing純正のメソッド(JFrame所属)があるのになんでAWT系列のややこしいwindowClosing書式(class java.awt.event.WindowAdapter のメソッド)を使うのか?
 まあ、やってる事は全く同じだからいいけど。


 ともかく、ベースが似ているので改造は楽に違いない、と思い早速同じ動作をさせることにする。


 ここで、以前小耳に挟んだ「swingは自動でダブルバッファを実現している」という機能をついでに試してみることにする。つまりAWTではシコシコ書いていたダブルバッファリングの操作をばっさり削除してグラフィクスコンテキストに色々書き込んでからrepaint()するだけ、としてみる。APIに載っていた「グラフィクスコンテキストのコピーを取って変更しろ」はひとまず無視する

import java.awt.event.* ;
import javax.swing.* ;
import java.awt.Graphics ;
import java.awt.Color ;

public class Graph8_2 extends JPanel implements MouseListener {
final static int lim = 256*2;//256だと追い越され得るから
static int[] bX = new int[lim]; //位置情報格納配列
static int[] bY = new int[lim]; //位置情報格納配列
static int[] bColor = new int[lim]; //色 情報格納配列
static int sta = 0; //配列最前列位置(後に描画)
static int end = 0; //配列最後尾位置(先に描画)
int r = 30; // 円の半径
final static Color bc = new Color(237,237,237); // 背景色
final static Color dc = Color.green; // 描画色

public Graph8_2() {
bX[0] = -100;
bY[0] = -100;
addMouseListener(this);
setBackground(bc);
}//this

public void paintComponent(Graphics g) {
super.paintComponent(g);
if(bX[end]>=0) {
if(sta != end && bColor[sta] == 237){bColor[sta] = 238;sta++;}
if(sta >= lim ){sta = 0;}
int i = sta;
while(true){
if(bColor[i] < 237){
bColor[i]++;
g.setColor(new Color(bColor[i],bColor[i],bColor[i]));
g.fillOval(bX[i]-r,bY[i]-r,r*2,r*2);
}
if(i == end){break;}
i++;
if(i >= lim){i = 0;}
}//for
}
}

public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
ublic void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) {
end++;
if(end>=lim) {end = 0;}
bX[end] = e.getX();
bY[end] = e.getY();
bColor[end] = 0;
}
public void mouseReleased(MouseEvent e) { }
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
frame.getContentPane().add( new Graph8_2() );
frame.setSize(400, 300);
frame.setVisible(true);
while(true){
try{
Thread.sleep(100);
}catch(InterruptedException ee){
}
frame.repaint();
}
}
}


 うまくいった。super.paintComponent(g)やgetContentPane()のように戸惑う命令もあるが、前のAWTでのダブルバッファよりも簡単なコードで・たまのちらつきもなく・クリックへの応答性もすこぶる良く、言うことなしである。これは使わない手は無い。
 今回は気持ちよく行ったので怒らずに終わる。


 しかし正直、swing以後でこれを教えない解説書は不勉強のそしりを免れないであろうと確かに思う。