dispose()



 最近やっているのは、円盤をアニメーション描画するプログラム。以前ウインドウに背景が映り込んで消えないバグがあったが、あのプログラムの発展系である。
Javaスタートブック:高田美樹:技術評論社
のP337にマウスクリックイベント検出による円を描くサンプルソースを基にしている。
 そのサンプルソースはこれ。


import java.awt.*;
import java.awt.event.*;
public class Mouse1 extends Frame implements MouseListener{
int r = 20;
  public Mouse1(){
setSize(400,300);
addMouseListener();
addWindowListener(new WindowAdapter(this){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public void paint(Graphics g){
}
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e){
}
public void mouseClicked(MouseEvent e){
Graphics g = getGraphics();
g.drawOval(e.getX()-r,e.getY()-r,r*2,r*2);
g.dispose();
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e){
}
public static void main(String[] args)
{
Frame w = new Mouse1();
w.show();
}
}
 まず、これで動いてしまう事に驚きである。なぜなら下から4行目、Frameクラスでwを宣言しているにもかかわらず、コンストラクターはMouse1クラスのコンストラクター。いいのかこんなんで。(あとで色々実験してみよう。)
 それはそれとして、これを改造してアニメーションさせると問題が二つ現れた。

 0.1秒毎に画像を更新して、クリックした場所に生んだ黒い円盤が徐々に淡くなり消えてしまうようにしたいわけだが、上の画像のようになってしまう(ソースは今日の最後においた)。問題点は

  • クリックした瞬間だけ更新される。
  • よって、クリックする前にbColor[i]=237(背景色)となってしまうと、どんなに黒かろうがそのまま永遠に残ってしまう。



 この問題を解決するためにいろいろいじっている内に、困ったことが浮かび上がってきた。グラフィックコンテキストとは何なのか、良く分からない。


g = getGraphics();
は、「グラフィックコンテキストを取得する。」という命令である事はどの本にも書いてある。
このgを命令の対象として指定しないと作図できないようなので、コンストラクターの引数に入れてなんとかメインスレッドに持ち込んだが、これがそもそも何なのかが良く分からないのだ。
JavaAPIにも「戻り値:このコンポーネントのグラフィックスコンテキスト。」とある。
上記の本には「必要なGraphicsクラスのオブジェクトは【↑】で取得できます。」とある。
で、”dispose()によってこれを「解放します。」”と書いてある。
(描画について描いてない本にはGraphicsそのものすら書いてないこともあるが、それは措く。)
JavaAPIを見ると(なんと15個も同名のメソッドが並んでいるが)、その説明には「このグラフィックスコンテキストを破棄して、使用中のシステムリソースがあればそれを解放します。Graphics オブジェクトを dispose の呼び出し後に使用することはできません。(←そのくせSystem.out.print(g)の結果は何の変化も無いが)【後略】」とある。


 はい、これでグラフィックコンテキストの意味と扱い方が分かった素人の人、手を挙げて!


 聞くまでも無いが
分かるわけねーだろ!


グラフィックコンテキストとは何なのか?
いつ生まれ、
またはどのようにつくり、
何を保持し、
何ができて、
何ができなくて、
破棄されると何がどうなるのか?
その説明もなしにどう使いこなせと?


おのれら解説本は
あたかも


新人「初めまして先輩方。dispose()とはどういう命令なのでしょうか?」
先輩A「あぁら!なんてこと!こんなことも知らない子がここに入ってくるなんて!」
先輩B「仕方ないじゃない。この子アマチュアなんですのよ。おーほほほほほ。」
先輩A「しょうがないわねぇ。あなたにはまだ早いでしょうけれど教えて差し上げますわ。dispose()とはグラフィックコンテキストを破棄する命令よ。破棄されたオブジェクトは使えなくなるの。」
新人「あの・・・グラフィックコンテキストって何でしょうか?本には説明が載ってないのですが・・・。それに、破棄された後もウインドウ上の画像もウインドウ自体も残ってますし、System.out.print(g)した結果も前後で変わらないんですが・・・。」
先輩B「まあ!今の説明で分からないって言うの!?まるでAさんの説明が悪かったみたいな言い草じゃなくってっ!?今のはdispose()の標準的な説明ですのよ!」
先輩A「行きましょBさん!こんなおバカな子を相手にしてたらおバカが伝染ってしまいましてよ!」


てな感じの先輩方かっちゅーの()!




 オマケで、改造したソース(うまく動かない)を付けよう。見なくても問題は無い。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Circle1 extends JFrame implements MouseListener{
static Graphics g;
public static void main(String[] args){
Circle1 w = new Circle1();
}
public Circle1(){
setVisible(true);
setSize(500,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addMouseListener(this);
addWindowListener(new WindowAdapter(){
public void windowCloseing(WindowEvent e){
System.exit(0);
}
});
g = getGraphics();
mainThread mt = new mainThread(g);
mt.start();
}

// public void paint(Graphics g){//←これは
// }//←誤動作の原因だったので削除してある。

public void mousePressed(MouseEvent e ){}
public void mouseReleased(MouseEvent e ){}
public void mouseClicked(MouseEvent e ){
mainThread.g = getGraphics();
mainThread.end++; //いつかオーバーフローするが気にしない。
if(mainThread.end>255) {mainThread.end = 0;}
mainThread.bX[mainThread.end] = e.getX();
mainThread.bY[mainThread.end] = e.getY();
mainThread.bColor[mainThread.end] = 0;//値の更新
}
public void mouseEntered(MouseEvent e ){}
public void mouseExited(MouseEvent e ){}
}
//ほんとは一つのクラスにしたかったのだが、
//Runnableをimplementするとうまく動かなかったので
//泣く泣く分離
class mainThread extends Thread{
static int[] bX = new int[256]; //位置情報格納配列
static int[] bY = new int[256]; //位置情報格納配列
static int[] bColor = new int[256]; //色 情報格納配列
static int sta = 0; //配列最前列位置(後に描画)
static int end = 0; //配列最後尾位置(先に描画)
static int r = 20;
static Graphics g;
mainThread(Graphics g){
this.g = g;
}
public void run(){
for(int k=0;k<256;k++){
bX[k] = 0;
bY[k] = 0;
bColor[k] = 237;
}//for
//描画無限ループ
while(true){
for(int i = sta ; i <= end ; i++){
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);
}
}//for
g.dispose();
if(sta != end && bColor[sta] == 237){bColor[sta] = 238;sta++;}
try{
sleep(100);
}catch(InterruptedException ee){}
}
}//run
}