前a

スレッドを使って(別の方法)

今回の目標

スレッドを使えばpaintImmediatelyを使わずに動かすことができます。動いている間もボタンが使えますから、複数の●を同時に動かせますし、green, blue ボタンも生きていますからこのようにいつでもランダムな円を描き加えることができます。

moveDisk

時間のかかる作業は別の人に任せて

プログラムは決められた順番にしたがって作業をしていきます。この一連の作業の流れをスレッドといいます。

イベントを待ってボタンを押されたらactionPerformed()を実行するというのも一つのスレッドになっています。javaのイベントのスレッドをイベントディスパッチスレッド(EDT)と言います。

このイベントディスパッチスレッド内で時間のかかる仕事を入れてしまうと次のイベントが起こっても対応できません。そこで、時間のかかる仕事をEDTとは別のスレッドでやらせようという作戦です。

今回は円を描いてそれをゆっくり動かす仕事を別のスレッドにさせて、EDTはボタンのクリックを監視する作業にもどります。

ファイル名 MovDisk2.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;

public class MovDisk2 extends JFrame implements ActionListener{
    JButton rbtn;
    JButton gbtn;
    JButton bbtn;
    MyPanel mypnl;
    JPanel  btnpnl;
    //コンストラクタ
    public MovDisk2() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("MovDisk");
        mypnl = new MyPanel(400,400);
        rbtn = new JButton("start"); //今回はこれだけ
        gbtn = new JButton("green");
        bbtn = new JButton("blue");
        btnpnl = new JPanel();
        btnpnl.setLayout(new GridLayout(1,3,0,0));
        btnpnl.add(rbtn);
        btnpnl.add(gbtn);
        btnpnl.add(bbtn);
        setLayout(new BorderLayout());
        add(mypnl, BorderLayout.CENTER);
        add(btnpnl,BorderLayout.SOUTH);
        rbtn.addActionListener(this);
        gbtn.addActionListener(this);
        bbtn.addActionListener(this);
        pack();
        setVisible(true);
    } //end of MovDisk2()コンストラクタ
    //イベント処理
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == rbtn) {
            Thread thread = new MakeDisk6Move(mypnl);
            thread.start();
        }
        if (e.getSource() == gbtn) {
            mypnl.drawRdm('g');
            mypnl.repaint();
        }
        if (e.getSource() == bbtn) {
            mypnl.drawRdm('b');
            mypnl.repaint();
        }
    } //end of actionPerformed
    public static void main(String[] args){
        MovDisk2 myframe = new MovDisk2();
    } // end of main
} // end of class MovDisk2

//クラス
class MyPanel extends JPanel{
    Color c = new Color(0,0,0);  //楕円の色(drawRdmで使用)
    Color bc= new Color(255,255,191);  //背景の色
    BufferedImage buffimg;
    Graphics bfg;
    public MyPanel(int width, int height){
        buffimg = new BufferedImage(
                 width,
                 height,
                 BufferedImage.TYPE_INT_RGB);
        bfg = buffimg.createGraphics();
        bfg.setColor(bc);
        bfg.fillRect(0, 0, width, height);
        setPreferredSize(new Dimension(width,height));
     }

    @Override
    public void paintComponent(Graphics myg){
        super.paintComponent(myg);
        myg.drawImage(buffimg, 0, 0
           ,getSize().width, getSize().height,this);
           //getSize().widthはMyPanelのインスタンスの幅
     }
     //円を動かすメソッド→下記クラスに移動

     //ランダムに円を描くメソッド
    public void drawRdm(char rgb) {
        for(int i=0; 10>i; i++){
            nextColor(rgb);
            bfg.setColor(c);
            int x = (int)(400*Math.random());
            int y = (int)(400*Math.random());
            int h = (int)(50*Math.random()+5);
            bfg.fillOval(x-h/2,y-h/2,h,h);
          }
     }
     //色を変化させるメソッド
    public void nextColor(char rgb){
        int r=0;
        int g=0;
        int b=0;
        if (rgb=='r'){
            r = (int)(r + 256*Math.random());
         }
        if (rgb=='g'){
            g = (int)(g + 256*Math.random());
         }
        if (rgb=='b'){
            b = (int)(b + 256*Math.random());
         }
        c = new Color(r,g,b);
     }
} // end of class MyPanel

//クラス
class MakeDisk6Move extends Thread { //add
    MyPanel pnl;
    BufferedImage image;
    Graphics bfg;
    int x = 100;
    int y ;
    int d = 10;
    int dx = 10;
    int xmax,ymax;
    //コンストラクタ
    public MakeDisk6Move(MyPanel pn) {
        pnl   = pn;
        image = pn.buffimg;
        bfg = image.createGraphics();
        xmax = image.getWidth();
        ymax = image.getHeight();
        y = (int)(ymax*Math.random());
     }

    @Override  //add
    public void run() { //add
        bfg.setColor(Color.red);
        while ( xmax > x ){
            bfg.fillOval(x-d/2,y-d/2,d,d);
            pnl.repaint();
            x+=dx;
            //100ms(0.1秒)停止
            try {
                Thread.sleep(100);
              }
            catch(InterruptedException ex) {
                System.err.println(ex);
              }
        }//end of while
    }//add end of run
}//end of class MakeDisk6Move

強調部分が主要な変更です。

一番大きな変更はmypnl.MakeDisk6Move()メソッドを独立したクラスにしたことです。そのために最後に持っていっています。

したがってイベント処理(actionPerformed)で、mypnl.moveDisk()の代わりにスレッドの作成(new MakeDisk6Move())実行(start)をしています。

new MakeDisk6Move(mypnl);でmypnlを渡しています。MakeDisk6Moveではコンストラクタでそれをpnlでうけrepaint()を指令します。またそのbuffimgをimageという名前でうけてその大きさをを調べ、image.createGraphics()でGraphicsを取得して使います。

実行すると次の様になります。

moveDisk

課題

1.

別スレッドで実行されることを確認しなさい。

ファイル名 MoveDisk2.java

もくじ


Javaプログラミング
聖愛中学高等学校
http://www.seiai.ed.jp/
Dec.2009
Nov.2011