Vectorクラス


配列のサイズ変更

前回のMouseDrawでは,線分を覚えておくためにLineの配列を使ったが,配列 の大きさはあらかじめ決めて確保してあり,それを超えた時の処理を書いてい なかった.

Java言語では配列のサイズをあとから変更することはできないようになって いるので,配列の大きさが足りなくなったら,新しくより大きな配列オブジェ クトを作成して(よく使われるのはこれまでのサイズの2倍),古い配列の内容 をコピーして使う方法である.

前のプログラムで,配列をどこまで使っているかを表すlineCountが増えるの は,マウスが離された時だけなので,以下のように置き換えてみることができ る.

  public void mouseReleased(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseUp("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目の始点を変更
    lines[lineCount].end_x=mx;
    lines[lineCount].end_y=my;
     // lineCountを増やす
    lineCount++;
    if(lineCount>=lines.length){
      Line[] newLines=new Line[lines.length*2];
      int i;
      for(i=0;i< lines.length;i++)
	newLines[i]=lines[i];
      lines=newLines;
    }
    dragging=false;
     // 再表示をおこなう
    repaint();
  }
なお,
      int i;
      for(i=0;i< lines.length;i++)
	newLines[i]=lines[i];
のように,配列から配列へのコピーは, Systemクラスの arraycopyメソッドを使って,以下のように書くことができる.
      System.arraycopy(lines,0,newLines,0,lines.length);

配列を管理するクラス

上の例では,配列の要素数を増やすのがプログラム上の1個所だったので,特 に問題なかったが,要素が増えるのが何カ所もある場合は,そのたびごとに上 のようなコードを挿入しなくてはいけない.その手間を省くために,Lineの配 列を管理するためのクラスを作るとプログラムがシンプルになる.

配列を管理するためにはどのような操作が必要かを考えて,クラスの設計を してみる.

仕様が決まったところで,クラスを作成してみる.
class LineArray{
  Line lines[];
  int lineCount;
  LineArray(){
    lines=new Line[10];
    lineCount=0;
  }
  int size(){
    return lineCount;
  }
  void addElement(Line line){
    lines[lineCount]=line;
    lineCount++;
    if(lineCount>=lines.length){
      Line[] newLines=new Line[lines.length*2];
      System.arraycopy(lines,0,newLines,0,lines.length);
      lines=newLines;
    }
  }
  Line elementAt(int index){
    return lines[index];
  }
}

これを使って,MouseDraw全体を書き直したのが以下のプログラムである.
  // AWTを使うため,
import java.awt.*;
  // イベント駆動関係のクラスを用いるため
import java.awt.event.*;

  // 線分のクラスを定義する.
class Line{
  // 始点,終点のX座標,Y座標を int で保持する.
  public int start_x,start_y,end_x,end_y;
  // Lineのコンストラクタ
  public Line(int x1,int x2,int x3,int x4){
   start_x=x1;
   start_y=x2;
   end_x=x3;
   end_y=x4;
  }
}

class LineArray{
  Line lines[];
  int lineCount;
  LineArray(){
    lines=new Line[10];
    lineCount=0;
  }
  int size(){
    return lineCount;
  }
  void addElement(Line line){
    lines[lineCount]=line;
    lineCount++;
    if(lineCount>=lines.length){
      Line[] newLines=new Line[lines.length*2];
      System.arraycopy(lines,0,newLines,0,lines.length);
      lines=newLines;
    }
  }
  Line elementAt(int index){
    return lines[index];
  }
}

 // インタフェースの実装では 「implements インタフェース名」と書く
 // 複数書く場合は,カンマで区切る
class MouseDraw extends Frame implements KeyListener, MouseListener, MouseMotionListener{
   // Lineの配列を保持するLineArrayクラスの変数 lineArrayの宣言
  LineArray lineArray;
   // マウスをドラッグ中かどうかを示す boolean型(真偽値)の変数draggingの宣言
  boolean dragging;
   // 表示する色を保持する変数
  Color lineColor;
   // コンストラクタの宣言
  public MouseDraw(String title){
     // 親クラス Frameのコンストラクタの宣言
    super(title);
    lineArray=new LineArray();
     // ドラッグ中ではない
    dragging=false;
     // 線の色は黒に
    lineColor=Color.black;
      // GUI部品と,Event Listenerを関連づける
    addKeyListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
  }
  public static void main(String args[]) {
     // MouseDrawのインスタンスを作成 frameに代入
    MouseDraw frame=new MouseDraw("MouseDraw");
     // サイズを 600x400に設定
    frame.setSize(600,400);
     // 表示する.
    frame.setVisible(true);
  }
  Image offScreenImage;
  Graphics offScreenGraphics;
  public void update(Graphics g){
    if(offScreenImage==null){
      offScreenImage=createImage(600,400); // オフスクリーンイメージを600x400のサイズで作成
      offScreenGraphics=offScreenImage.getGraphics(); // オフスクリーンイメージに描画するための Graphics オブジェクト
    }
    paint(offScreenGraphics); // 次の画面のイメージを作る.
    g.drawImage(offScreenImage,0,0,this); // イメージを本物のスクリーンに書き込む
  }
   // offScreenImageの書き直しをする際に呼ばれる
  public void paint(Graphics g){
    int i;
      // 白で(0,0)-(600,400)を塗り潰す
    g.setColor(Color.white);
    g.fillRect(0,0,600,400);
      // 色を設定
    g.setColor(lineColor);
    int size=lineArray.size();
    if(dragging) size--;
    for(i=0;i< size;i++){
      Line l=lineArray.elementAt(i);
      g.drawLine(l.start_x,l.start_y,l.end_x,l.end_y);
    }
     // マウスをドラッグ中の時は
    if(dragging){
       // 赤い色で
      g.setColor(Color.red);
       // lines[lineCount] を描画する.
      Line l=lineArray.elementAt(i);
      g.drawLine(l.start_x,l.start_y,l.end_x,l.end_y);
    }
  }
   // KeyListenerを実装するためのメソッド
  public void keyPressed(KeyEvent e){
     // イベントからキーのコードを取り出す
    int key=e.getKeyChar();
     // デバッグ用の表示
    System.out.println("keyPressed("+e+","+key+")");
     // 入力が 'q'の時は終了する
    if(key=='q') System.exit(0);
  }
   // 要らないイベントに対応するメソッドも中身は空で書いておく必要がある.
  public void keyReleased(KeyEvent e){}
  public void keyTyped(KeyEvent e){}
   // MouseListenerを実装するためのメソッド
  public void mousePressed(MouseEvent e){
     // 押された時のマウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mousePressed("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目に線分を登録
    lineArray.addElement(new Line(mx,my,mx,my));
     // ドラッグ中であることを示す
    dragging=true;
     // 再表示をおこなう
    repaint();
  }
   // マウスのボタンが離された時のイベント
  public void mouseReleased(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseUp("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目の始点を変更
    Line l=lineArray.elementAt(lineArray.size()-1);
    l.end_x=mx;
    l.end_y=my;
    dragging=false;
     // 再表示をおこなう
    repaint();
  }
  public void mouseClicked(MouseEvent e){}
  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
   // MouseMotionListenerを実装するためのメソッド
  public void mouseDragged(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseDrag("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目の始点を変更
    Line l=lineArray.elementAt(lineArray.size()-1);
    l.end_x=mx;
    l.end_y=my;
     // 再表示をおこなう
    repaint();
  }
  public void mouseMoved(MouseEvent e){}
}
なお,lineArray中の lineCountをマウスを離した時に増やす代わりに,マウ スを押した際に増やすようにしたため,paint部分が以前と少し変更されてい ることに注意されたい.

Vectorクラス

可変長の配列を扱いたいという要求は多いため,システムに Vectorクラ スというクラスが用意されている.これは,上で定義したようなメソッド の他に,要素を探したり,途中の要素を削除したりする機能もある.ただし, 以下の点は注意が必要である. 上のプログラムを Vectorクラスを使って書き直した例をあげる.さきほどの 例との変更部分は赤くしてある.
  // AWTを使うため,
import java.awt.*;
  // イベント駆動関係のクラスを用いるため
import java.awt.event.*;
  // Vectorクラスを用いるため
import java.util.*;

  // 線分のクラスを定義する.
class Line{
  // 始点,終点のX座標,Y座標を int で保持する.
  public int start_x,start_y,end_x,end_y;
  // Lineのコンストラクタ
  public Line(int x1,int x2,int x3,int x4){
   start_x=x1;
   start_y=x2;
   end_x=x3;
   end_y=x4;
  }
}
 // インタフェースの実装では 「implements インタフェース名」と書く
 // 複数書く場合は,カンマで区切る
class MouseDraw extends Frame implements KeyListener, MouseListener, MouseMotionListener{
   // Lineの配列を保持するVectorクラスの変数 lineArrayの宣言
  Vector lineArray;
   // マウスをドラッグ中かどうかを示す boolean型(真偽値)の変数draggingの宣言
  boolean dragging;
   // 表示する色を保持する変数
  Color lineColor;
   // コンストラクタの宣言
  public MouseDraw(String title){
     // 親クラス Frameのコンストラクタの宣言
    super(title);
    lineArray=new Vector();
     // ドラッグ中ではない
    dragging=false;
     // 線の色は黒に
    lineColor=Color.black;
      // GUI部品と,Event Listenerを関連づける
    addKeyListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
  }
  public static void main(String args[]) {
     // MouseDrawのインスタンスを作成 frameに代入
    MouseDraw frame=new MouseDraw("MouseDraw");
     // サイズを 600x400に設定
    frame.setSize(600,400);
     // 表示する.
    frame.setVisible(true);
  }
  Image offScreenImage;
  Graphics offScreenGraphics;
  public void update(Graphics g){
    if(offScreenImage==null){
      offScreenImage=createImage(600,400); // オフスクリーンイメージを600x400のサイズで作成
      offScreenGraphics=offScreenImage.getGraphics(); // オフスクリーンイメージに描画するための Graphics オブジェクト
    }
    paint(offScreenGraphics); // 次の画面のイメージを作る.
    g.drawImage(offScreenImage,0,0,this); // イメージを本物のスクリーンに書き込む
  }
   // offScreenImageの書き直しをする際に呼ばれる
  public void paint(Graphics g){
    int i;
      // 白で(0,0)-(600,400)を塗り潰す
    g.setColor(Color.white);
    g.fillRect(0,0,600,400);
      // 色を設定
    g.setColor(lineColor);
    int size=lineArray.size();
    if(dragging) size--;
    for(i=0;i< size;i++){
      Line l=(Line)lineArray.elementAt(i);
      g.drawLine(l.start_x,l.start_y,l.end_x,l.end_y);
    }
     // マウスをドラッグ中の時は
    if(dragging){
       // 赤い色で
      g.setColor(Color.red);
       // lines[lineCount] を描画する.
      Line l=(Line)lineArray.elementAt(i);
      g.drawLine(l.start_x,l.start_y,l.end_x,l.end_y);
    }
  }
   // KeyListenerを実装するためのメソッド
  public void keyPressed(KeyEvent e){
     // イベントからキーのコードを取り出す
    int key=e.getKeyChar();
     // デバッグ用の表示
    System.out.println("keyPressed("+e+","+key+")");
     // 入力が 'q'の時は終了する
    if(key=='q') System.exit(0);
  }
   // 要らないイベントに対応するメソッドも中身は空で書いておく必要がある.
  public void keyReleased(KeyEvent e){}
  public void keyTyped(KeyEvent e){}
   // MouseListenerを実装するためのメソッド
  public void mousePressed(MouseEvent e){
     // 押された時のマウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mousePressed("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目に線分を登録
    lineArray.addElement(new Line(mx,my,mx,my));
     // ドラッグ中であることを示す
    dragging=true;
     // 再表示をおこなう
    repaint();
  }
   // マウスのボタンが離された時のイベント
  public void mouseReleased(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseUp("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目の始点を変更
    Line l=(Line)lineArray.elementAt(lineArray.size()-1);
    l.end_x=mx;
    l.end_y=my;
    dragging=false;
     // 再表示をおこなう
    repaint();
  }
  public void mouseClicked(MouseEvent e){}
  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
   // MouseMotionListenerを実装するためのメソッド
  public void mouseDragged(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseDrag("+e+","+mx+","+my+")");
     // 配列linesのlineCount番目の始点を変更
    Line l=(Line)lineArray.elementAt(lineArray.size()-1);
    l.end_x=mx;
    l.end_y=my;
     // 再表示をおこなう
    repaint();
  }
  public void mouseMoved(MouseEvent e){}
}

アニメーション