Nanashi-softプログラマ専用Javaアプリケーション


◇Javaアプリケーション-裏画面を使う-

◎裏画面を使う
点を打つサンプルを実行して,ウィンドウサイズを変えたりしてみると,白くクリアされてしまいます
これは,処理を行った画面が保持されていないからです

裏画面を作成し,そこに処理結果を書き込み,裏画面を実画面にコピーする事で,これを防ぐ事ができます

まず,裏画面用の変数をグローバル変数で定義します
クラス宣言のすぐ下に記述します

public class fst extends Frame{
  static Image ura;
  static Graphics ug;
  public static final void main(final String[] args){

そして,ウィンドウ表示後に生成します
このタイミングであれば確実にキャンバスの実体がある為です。これより前だとタイミングによってはヌルポインタエラーが出ます

    //ウィンドウ表示
    app.setVisible(true);
    //裏画面生成
    ura = cvs.createImage(240, 240);
    ug = ura.getGraphics();
    //無限ループ
    while (true){

そして,ループ中で ugを使用して描画します
paint内に記述していたものを移して,g.の部分を ug.に変えると良いでしょう
※この部分は,後のソース参照のこと

そして,paint内で,裏画面を実画面にコピーします

    public void paint(Graphics g){
      //裏画面を実画面にコピー
      g.drawImage(ura, 0, 0, null);
    }

◎ソース(注意:未完成版)

import java.awt.*;
import java.awt.event.*;

public class fst extends Frame{
  static Image ura;
  static Graphics ug;

  public static final void main(final String[] args){
    //ウィンドウ生成
    Frame app=new Frame();
    //タイトル設定
    app.setTitle("Title");
    //ウィンドウサイズ設定(タイトルや枠も含んだサイズ)
    app.setSize(240, 240);
    //キャンバスを配置
    fstCanvas cvs=new fstCanvas();
    app.add(cvs);
    //ウィンドウ表示
    app.setVisible(true);
    //裏画面生成
    ura = cvs.createImage(240, 240);
    ug = ura.getGraphics();
    //無限ループ
    while (true){
      //座標用変数
      int x, y;
      //カラー用変数
      int red, green, blue;

      //ランダムに座標を生成
      x = (int)(Math.random() * 240);
      y = (int)(Math.random() * 240);

      //ランダムにカラーを生成
      red = (int)(Math.random() * 256);
      green = (int)(Math.random() * 256);
      blue = (int)(Math.random() * 256);

      //ペンの色を変える
      ug.setColor(new Color(red, green, blue));

      //点を描画する
      ug.drawLine(x, y, x, y);

      //画面再描画
      cvs.repaint();
    }
  }

  static class fstCanvas extends Canvas{
    public void paint(Graphics g){
      //裏画面を実画面にコピー
      g.drawImage(ura, 0, 0, null);
    }

    //updateメソッドを乗っ取って,画面クリアを防ぐ
    public void update(Graphics g){
        paint(g);
    }
  }
}

◎描画タイミングの重要性
上記ソースをビルドして実行してみて下さい
運が良い人は結構多くの点が表示されますが,いつか止まります
環境依存なので,人それぞれだと思います

止まる原因は詳しくは分かりませんが,以下のようなマズい事が起っています
上記ソースでは,
裏画面描画→repaint()→裏画面描画→repaint()→裏画面描画→
と連続して命令を出していますが,描画が完了した事を確認していません
よって,1回目のrepaint()発行後に,まだpaintが終わる前に2回目のreapint()が発行された場合,どのように動作するのかわからない事になります

よって,
裏画面描画→repaint()→描画完了確認→裏画面描画→repaint()→描画完了確認→裏画面描画→
のようにしなければなりません

動画をイメージすると分かり易いと思います
1コマ目生成→描画しろ→描画完了→2コマ目生成→描画しろ→描画完了→
のようにしっかり描画した事を確認しなければ,2コマ目が飛んで3コマ目が表示されてしまい,カクカクした映像になるでしょう

◎ソース
単純にフラグを使用して描画完了をチェックしてみました

import java.awt.*;
import java.awt.event.*;

public class fst extends Frame{
  //裏画面用変数
  static Image ura;
  static Graphics ug;
  //描画中フラグ
  static Boolean pflg=false;

  public static final void main(final String[] args){
    //ウィンドウ生成
    Frame app=new Frame();
    //タイトル設定
    app.setTitle("Title");
    //ウィンドウサイズ設定(タイトルや枠も含んだサイズ)
    app.setSize(240, 240);
    //キャンバスを配置
    fstCanvas cvs=new fstCanvas();
    app.add(cvs);
    //ウィンドウ表示
    app.setVisible(true);
    //裏画面生成
    ura = cvs.createImage(240, 240);
    ug = ura.getGraphics();
    //無限ループ
    while (true){
      //描画チェックフラグが立っていなければ描画する
      if (pflg == false){
        //座標用変数
        int x, y;
        //カラー用変数
        int red, green, blue;

        //ランダムに座標を生成
        x = (int)(Math.random() * 240);
        y = (int)(Math.random() * 240);

        //ランダムにカラーを生成
        red = (int)(Math.random() * 256);
        green = (int)(Math.random() * 256);
        blue = (int)(Math.random() * 256);

        //ペンの色を変える
        ug.setColor(new Color(red, green, blue));

        //点を描画する
        ug.drawLine(x, y, x, y);

        //描画中フラグを立てる
        pflg = true;
        //画面再描画
        cvs.repaint();
      }
    }
  }

  static class fstCanvas extends Canvas{
    public void paint(Graphics g){
      //描画中フラグが立っていたら処理する
      if (pflg == true){
        //裏画面を実画面にコピー
        g.drawImage(ura, 0, 0, null);
        //描画中フラグをクリア
        pflg = false;
      }
    }

    //updateメソッドを乗っ取って,画面クリアを防ぐ
    public void update(Graphics g){
        paint(g);
    }
  }
}

これを実行してみると,先程よりも随分遅いと思います
それだけ描画待ち時間があると言うことで,裏画面を2枚にして描画待ち中に次の画面を用意するなど,時間をいかに有効に使うかはプログラマの腕の見せ所でしょう


TOPプログラマ専用Javaアプリケーション