Javaプログラミング基礎

講義資料

今回は、簡単な絵をウィンドウ上に描いたり、 マウスで操作ができるようなプログラムについて学びます。 グラフィックス表示を行うための クラスライブラリの使い方を紹介します。

Javaでグラフィックス表示を行うために 代表的なAWTとSwingと呼ばれる機能を使います。

グラフィックスにおける座標の扱い

Javaをはじめとする多くのグラフィックス環境では、 表示画面を細かい点の集まりとして扱います。この点のことを画素といいます。 そして、この点が画面上のどの位置かを示すために、 左上を原点 (0,0) とした座標を用います。 例えば、幅 640 、高さ 480 の大きさのウィンドウの座標は 下の絵のようになります。

数学のグラフの y 座標を上下逆にしたものだと考えることができます。

ウィンドウ上に位置を指定して図形や文字を書く場合や、 ウィンドウ上の範囲など指定する場合、 すべてこの「座標」を使います。

グラフィックスの基本

例題: ウィンドウを開くプログラム

さっそく、ウィンドウを開くプログラムを作りましょう。 まだ、ウィンドウを開くだけで何も中身が表示されませんが、 後の例題で様々な図形や文字の表示方法を学ぶことになります。 (ファイル名: BasicWindow.java)

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

class BasicWindow {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Basic Window");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	frame.setVisible(true);
    }
}

このプログラムを実行してみましょう。 中身のないウィンドウが表示されましたね。

プログラムを上から順に見ていきましょう。

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

上の部分は、Javaのクラスライブラリの中から「java.awt」と 「javax.swing」というパッケージにあるクラスを、 このプログラム内でデフォルトで使うことができるようにするための記述です。

	JFrame frame = new JFrame();

クラス JFrame は、ウィンドウの「枠」を表示させるためのクラスです。 JFrame のオブジェクトを生成し、 所定のメソッドを実行することによって、 画面にウィンドウを表示することができます。

	frame.setTitle("Basic Window");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	frame.setVisible(true);

上のプログラムは、JFrame オブジェクト frame に所定の値を設定し、 ウィンドウを表示するためのメソッドの実行です。 上から順番に、ウィンドウのタイトルを設定し、 大きさを設定し、 ウィンドウを閉じたときにプログラム自体を終了する設定をし、 最後にウィンドウを表示しています。

例題: 図形を書く準備

上の例題のプログラムを元に、 図形を表示させることを考えてみましょう。

クラス JFrame は、ウィンドウの「枠」を表示することしかできません。 ウィンドウの上に何か表示するには、 表示するための「土台」にあたるものが必要です。 この土台のことを「コンテナ (container)」といいます。 ウィンドウ上で良く使われるコンテナは、クラス JPanel です。

この段階では、図形を書く準備はできたことになりますが、 まだ、具体的な図形は書いていません。

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

class BasicPanel {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Basic Panel");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setBackground(Color.white);
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

前の例題から付け加えたのは以下の部分です。

        JPanel panel = new JPanel();
        panel.setBackground(Color.white);
	frame.getContentPane().add(panel);

図形を書くためのコンテナであるクラス JPanel のオブジェクトを生成し、 背景色を白 (Color.white) に設定しています。 次に、ウィンドウの中に panel が表示されるように、 frame に panel を加えています。

例題: 図形を表示する

上の例題のプログラムをベースに、簡単な図形を書いてみます。 図形を書く方法の一つに、コンテナであるクラス JPanel を継承し、 図形表示機能を付け加える方法があります。 (BasicShapes.java)

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

class BasicShapes {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Basic Shapes");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel {
    public MyPanel() {
	setBackground(Color.white);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	// ウィンドウ内に描画したい図形をここに書く
	g.setColor(Color.red);
	g.fillRect(50,100,100,100);
	g.drawRect(200,100,100,100);

	g.setColor(Color.black);
	g.drawLine(350,100,450,200);

	g.setColor(Color.gray);
	g.fillOval(50,240,100,100);
	g.drawOval(200,240,100,100);

	g.setColor(Color.black);
	g.drawString("Welcome to java graphics.", 10, 20);
    }
}

クラス MyPanel が、元のクラス JPanel を継承して定義したクラスです。 図形を表示するためには、 メソッド paintComponent をオーバライドし、 図形を書くための処理を書き加えます。 メソッド paintComponent を見てみましょう。

	g.setColor(Color.red);
	g.fillRect(50,100,100,100);
	g.drawRect(200,100,100,100);

上のプログラムは、まず描画色を赤に設定し、 中身の塗りつぶされた四角形を描き、 枠だけの四角形を描いています。

	g.setColor(Color.white);
	g.drawLine(350,100,450,200);

	g.setColor(Color.gray);
	g.fillOval(50,240,100,100);
	g.drawOval(200,240,100,100);

	g.setColor(Color.black);
	g.drawString("Welcome to java graphics.", 10, 20);

それぞれ、drawLine は、線を描くためのメソッド、 fillOval は、塗りつぶされた円を描くためのメソッド、 drawOval は、円を描くためのメソッド、 drawString は、文字列を描くためのメソッドです。

各メソッドの使いかたを簡単にまとめます。 詳しくは Java SDK JDK 5.0 ドキュメント の クラス Graphics の説明を参照してください。

setColor(color)
描画色を引数で指定された色に変更します。 指定可能な色には主に以下のようなものがあります。
drawLine(x1, y1, x2, y2)
座標 (x1, y1) と (x2, y2) を結ぶ線を描きます。
drawOval(x, y, width, height)
座標 (x, y) を左上とする、高さ width、幅 height の円 (楕円) を描きます。
drawRect(x, y, width, height)
座標 (x, y) を左上とする、高さ width、幅 height の四角形を描きます。
drawString(string, x, y)
座標 (x, y) に文字 string を描きます。
fillOval(x, y, width, height)
座標 (x, y) を左上とする、高さ width、幅 height の塗りつぶされた円 (楕円) を描きます。
fillRect(x, y, width, height)
座標 (x, y) を左上とする、高さ width、幅 height の塗りつぶされた四角形を描きます。

マウスやキーボードからの入力を受け付ける

ウィンドウ上で、マウスのクリックやキー入力などを行うと、 プログラムに対して「イベント(event)」という信号 (のようなもの) が発せられます。 プログラムではイベントを受け取り、 そのイベントに関するデータ (例えば、マウスの座標やキーの種類など) を 適切に処理します。

イベントが発生したときに実行される部分を イベントハンドラ (event handler) と呼びます。 Javaでは、イベントが発生したときに行うべき仕事を あらかじめメソッドとして書いておき、 イベントの発生に備えて登録しておきます。 このイベントハンドラをまとめたクラスを、 リスナ (listener) と呼びます。

例題: マウスのボタン操作を検出する

マウスのボタンの操作を検出するプログラムを示します。 (MouseChecker.java)

実際に実行して、マウスの反応を見てみましょう。

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

class MouseChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Mouse Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseListener {
    public MyPanel() {
	setBackground(Color.white);
	addMouseListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void mouseClicked(MouseEvent e) {
	System.out.println("マウスがクリックされました");
    }
    public void mouseEntered(MouseEvent e) {
	System.out.println("マウスがパネル内に入りました");
    }
    public void mouseExited(MouseEvent e) {
	System.out.println("マウスがパネル内から出ました");
    }
    public void mousePressed(MouseEvent e) {
	System.out.println("マウスのボタンが押されました");
    }
    public void mouseReleased(MouseEvent e) {
	System.out.println("マウスのボタンが離されました");
    }
}

下線で示した部分が、 マウスのボタン操作を検出し、処理するために必要な記述です。

import java.awt.event.*;

上の記述は、クラスライブラリのイベントに関するクラスを、 デフォルトで使えるようにするための記述です。

class MyPanel extends JPanel implements MouseListener

マウスのボタン操作に関するイベントを受け取るには、 インタフェース MouseListener を実装し、 マウスのボタンの押す操作、離す操作に対応したメソッドを作成する必要があります。

        addMouseListener(this);

上の記述では、このクラス (MyPanel) で、 マウスのボタン操作に関するイベントを受け取るように登録しています。

    public void mouseClicked(MouseEvent e)
    public void mouseEntered(MouseEvent e)
    public void mouseExited(MouseEvent e)
    public void mousePressed(MouseEvent e)
    public void mouseReleased(MouseEvent e)

上の5つのメソッドは、それぞれ、 マウスがクリックされたとき、マウスカーソルがウィンドウ内に入ったとき、 マウスカーソルがウィンドウ外に出たとき、 マウスのボタンが押されたとき、 マウスのボタンが離されたときの、 各タイミングで自動的に実行されるメソッドです。 これらのメソッドにイベントの種類によって適切な処理を書くことになります。

例題: マウスの動きを検出する

マウスのボタン操作に加えて、 マウスの動きを検出するプログラムを示します。 (MouseMotionChecker.java)

実際に実行して、マウスの反応を見てみましょう。

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

class MouseMotionChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Mouse Motion Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseListener,MouseMotionListener {
    public MyPanel() {
	setBackground(Color.white);

	addMouseListener(this);
	addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void mouseClicked(MouseEvent e) {
	System.out.println("マウスがクリックされました");
    }
    public void mouseEntered(MouseEvent e) {
	System.out.println("マウスがパネル内に入りました");
    }
    public void mouseExited(MouseEvent e) {
	System.out.println("マウスがパネル内から出ました");
    }
    public void mousePressed(MouseEvent e) {
	System.out.println("マウスのボタンが押されました");
    }
    public void mouseReleased(MouseEvent e) {
	System.out.println("マウスのボタンが離されました");
    }

    public void mouseDragged(MouseEvent e) {
	System.out.println("ドラッグ中のマウスの位置: " + e.getX() + "," + e.getY());
    }
    public void mouseMoved(MouseEvent e) {
	System.out.println("マウスの位置: " + e.getX() + "," + e.getY());
    }
}

下線で示した部分が、マウスの動きを検出するための記述です。

マウスの動きを検出するには、 インタフェース MouseMotionListener を実装し、 マウスが動いたときのイベントを処理するメソッドを用意します。 次に、addMouseMotionListener(this) で、 マウスが動いたときのイベントを受け取るように登録します。

ウィンドウ内でマウスの位置が変わると逐次イベントが発生し、 mouseDragged あるいは mouseMoved メソッドが自動的に実行されます。 これらのメソッドに、マウスが動いたときに行う仕事の内容を書くことになります。 また、そのときのマウスカーソルの位置 (座標) を取り出すことができます。 メソッド e.getX() でマウスカーソルのX座標、 メソッド e.getY() でY座標を得ることができます。

座標以外に取り出すことができる情報 (どのボタンが押されていたか、キーが同時に押されたいたか等) など詳しくは、 Java SDK JDK 5.0 ドキュメント の インタフェース MouseEvent の説明を参照してください。

例題: キーボード入力(1)

イベント処理に関する最後の話題として、 キーボードからの入力を受け取る方法を示します。 (KeyChecker.java)

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

class KeyChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Key Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements KeyListener {
    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void keyPressed(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が押されました");
    }
    public void keyReleased(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が離されました");
    }
    public void keyTyped(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "がタイプされました");
    }
}

プログラム全体の構造は、マウスに関するイベント処理のプログラムと同様です。 キー入力を検出するには、 インタフェース KeyListener を実装し、 キーボード入力に関するイベントを処理するメソッドを用意します。 次に、setFocusable(true) でキー入力を受け取る準備をし、 addKeyListener(this) で、 キー入力をしたときのイベントを受け取るように登録します。

キーを押したとき、キーを離したとき、キーをタイプしたとき、それぞれ メソッド keyPressed, keyReleased, keyTyped が自動的に実行されます。

メソッド e.getKeyChar() でキーの内容を取り出すことができます。 e.getKeyChar() の値は「1文字」を表す char 型です。 文字列を表す String オブジェクトに変換するには、

    e.geKeyChar().toString()

のように書きます。

矢印キーや、Alt, Control, Back Space などの制御キーを扱う方法など 詳しくは、 Java SDK JDK 5.0 ドキュメント の クラス KeyEvent の説明を参照してください。

例題: キーボード入力(2)

矢印キーの操作を検出するプログラムを示します。 (ArrowKeyChecker.java)

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

class ArrowKeyChecker {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Arrow Key Checker");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements KeyListener {
    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);
    }

    public void keyPressed(KeyEvent e) {
	if (e.getKeyCode() == KeyEvent.VK_DOWN)
	    System.out.println("↓");
	else if (e.getKeyCode() == KeyEvent.VK_UP)
	    System.out.println("↑");
	else if (e.getKeyCode() == KeyEvent.VK_LEFT)
	    System.out.println("←");
	else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
	    System.out.println("→");
	else {
	    System.out.println(e.getKeyChar());
	}
    }
    public void keyReleased(KeyEvent e) {
    }
    public void keyTyped(KeyEvent e) {
    }
}

例題: マウスカーソルの位置に文字を表示するプログラム

イベントを扱う簡単な例として、 マウスカーソル上にキーボードから入力した文字を表示するプログラムを示します。 (PutLetter.java)

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

class PutLetter {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Put Letter");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements MouseMotionListener, KeyListener {
    int mouseX, mouseY;
    String letter;

    public MyPanel() {
	setBackground(Color.white);

	setFocusable(true);
	addKeyListener(this);
	addMouseMotionListener(this);

	letter = "";
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	System.out.println("ウィンドウの内容が変更されたので再描画します");
	g.setColor(Color.black);
	g.drawString(letter, mouseX, mouseY);
    }

    public void mouseDragged(MouseEvent e) {
    }
    public void mouseMoved(MouseEvent e) {
	System.out.println("マウスの位置: " + e.getX() + "," + e.getY());
	mouseX = e.getX();
	mouseY = e.getY();
    }

    public void keyPressed(KeyEvent e) {
	System.out.println("キー " + e.getKeyChar() + "が押されました");
	char ch = e.getKeyChar();
	letter = Character.toString(ch);

	repaint();
    }
    public void keyReleased(KeyEvent e) {
    }
    public void keyTyped(KeyEvent e) {
    }
}

このプログラムでは、マウスの動きとキー入力に関するイベント処理を行うので、 インタフェース MouseMotionListener と KeyListener を実装します。

    int mouseX, mouseY;
    String letter;

クラス MyPanel では、 マウスカーソルの座標情報を入れるための int mouseX, mouseY と、 入力された文字を入れるための String letter の3つの属性を用意します。

マウスが移動した際に実行されるメソッド MouseMoved では、 マウスが移動するたびに、mouseX, mouseYの値を更新するようにします。

キーを押した際に実行されるメソッド KeyPressed では、 押した文字を letter に代入するようにします。 ここでメソッド repaint() の実行に注目してください。 メソッド repaint は、 ウィンドウ内の内容を更新したいときに、再度描画を行わせるメソッドです。 具体的には、repaint() を実行すると、 ウィンドウ内が一旦クリアされ、 メソッド paintComponent(Graphics g) が自動的に実行されるようになっています。 結果として、画面が書き換わり、 マウスカーソルの位置に入力した文字が表示されることになります。

メソッド paintComponent(Graphics g) は、 repaint() によって実行されるだけではありません。 複数のウィンドウが重なり、 このプログラムのウィンドウが後ろになってしまうと、 ウィンドウの中身が別のウィンドウにかくれて見えなくなります。 この状況でこのプログラムのウィンドウを最前面に移動させると、 ウィンドウの中身を新たに書き直さなければなりません。 このようなケースでも paintComponet(Graphics g) は実行されるのです。

アニメーションを行う

今日最後の話題はアニメーションです。 グラフィック表示を行う本格的なアニメーションを行うことを考えてみましょう。

アニメーションを行う基本的な考え方は、 1コマ1コマ絵を書き換えることです。 いままでのプログラムでは、ウィンドウに表示させたい図形は メソッド paintComponent(Graphics g) の中に書いてきました。 paintComponent(Graphics g) を定期的に実行することで、 画面を書き換えアニメーションを行うプログラムについて考えてみます。

例題: 簡単な図形の移動

ボールが左から右へ移動するアニメーションを考えてみます。 (SimpleAnimation.java)

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

class SimpleAnimation {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Simple Animation");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements Runnable {
    // ボールの位置
    private int position;

    public MyPanel() {
	setBackground(Color.white);

        // 10ミリ秒ごとに画面を書き換えるためのおまじない
	Thread refresh = new Thread(this);
	refresh.start();
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

        // アニメーションの1コマごとの処理をここに書く

        // 座標の計算
	position = position + 1;

        // 物体の描画
	g.setColor(Color.red);
	g.fillOval(position, 200, 50, 50);
    }

    // 10ミリ秒ごとに画面を書き換えるためのおまじない
    public void run() {
	while(true) {
	    repaint();
	    try {
		Thread.sleep(10);
	    }
	    catch(Exception e) {
	    }
	}
    }
}

下線で示した部分が、定期的に画面の書き換えを行わせるために必要な記述です。 詳しい説明は省略しますが、 これは「スレッド (thread)」と呼ばれる仕組みを使い、 メソッド run() を他のメソッドの処理と並行して動かしています。 メソッド run() の中では、 10ミリ秒おきにメソッド repaint() を実行しています。 したがって、10ミリ秒おきに paintComponent(Graphics g) によって、 画面の書き換えが行われることになります。

アニメーションの速度を調節するには、 下の部分の画面の書き換えの間隔を変更します。

		Thread.sleep(10);

単位はミリ秒です。

このプログラムでは、アニメーションの1コマごとの処理を メソッド paintComponent(Graphics g) に書きます。 具体的には、ボールの位置を右に1つずらして、 ボールを描画しています。 これが10ミリ秒ごとに実行されるので、 ボールが右に移動するように見えます。

例題: 跳ね返るボールのアニメーション(1)

お馴染みのボールが跳ね返るアニメーションを グラフィック表示してみましょう。 クラス Ball は、以前と同じ考え方で定義し、 アニメーション実行部分に組み入れています。 (BallAnimation.java)

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

class BallAnimation {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Ball Animation");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements Runnable {
    // ボールオブジェクト
    Ball ball;

    public MyPanel() {
	setBackground(Color.white);

        // ボールオブジェクトの生成
        // (初期位置, 初期速度, 移動範囲の情報を与えて初期化)
	ball = new Ball(100,100,2,1,0,0,610,430);

	Thread refresh = new Thread(this);
	refresh.start();
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

        // アニメーション1コマ分の移動処理
	ball.forward();

        // ボールの描画
	g.setColor(Color.red);
	g.fillOval(ball.getX(), ball.getY(), 20, 20);
    }

    public void run() {
	while(true) {
	    repaint();
	    try {
		Thread.sleep(10);
	    }
	    catch(Exception e) {
	    }
	}
    }
}

class Ball {
    private int x;
    private int y;
    private int vx;
    private int vy;
    private int left;
    private int right;
    private int top;
    private int bottom;

    public Ball(int x, int y, int vx, int vy, int l, int t, int r, int b) {
	this.x = x;
	this.y = y;
	this.vx = vx;
	this.vy = vy;
	right = r;
	left = l;
	top = t;
	bottom = b;
    }

    public void forward() {
	if (x + vx < left || x + vx > right) 
	    vx = -vx;
	if (y + vy < top || y + vy > bottom) 
	    vy = -vy;
	x = x + vx;
	y = y + vy;
    }

    public int getX() {
	return x;
    }

    public void setX(int x) {
	this.x = x;
    }

    public int getY() {
	return y;
    }

    public void setY(int y) {
	this.y = y;
    }
}

例題: ボールのアニメーション(2)

マウスの動きを検出する処理を加え、 ボールをドラッグして移動できる機能を加えた例を示します。 (BallAnimation2.java)

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

class BallAnimation2 {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Ball Animation");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements Runnable, MouseMotionListener {
    private Ball ball;

    public MyPanel() {
	setBackground(Color.white);
        // マウスを動かしたときのイベント処理を行うように登録
	addMouseMotionListener(this);

	ball = new Ball(100,100,1,1,0,0,610,430);

	Thread refresh = new Thread(this);
	refresh.start();
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	ball.forward();
	g.setColor(Color.red);
	g.fillOval(ball.getX(), ball.getY(), 20, 20);
    }

    // マウスをドラッグしたとき、その座標にボールを移動させる
    public void mouseDragged(MouseEvent e) {
	ball.setX(e.getX());
	ball.setY(e.getY());
    }
    public void mouseMoved(MouseEvent e) {
    }

    public void run() {
	while(true) {
	    repaint();
	    try {
		Thread.sleep(10);
	    }
	    catch(Exception e) {
	    }
	}
    }
}

class Ball {
    private int x;
    private int y;
    private int vx;
    private int vy;
    private int left;
    private int right;
    private int top;
    private int bottom;

    public Ball(int x, int y, int vx, int vy, int l, int t, int r, int b) {
	this.x = x;
	this.y = y;
	this.vx = vx;
	this.vy = vy;
	right = r;
	left = l;
	top = t;
	bottom = b;
    }

    public void forward() {
	if (x + vx < left || x + vx > right) 
	    vx = -vx;
	if (y + vy < top || y + vy > bottom) 
	    vy = -vy;
	x = x + vx;
	y = y + vy;
    }

    public int getX() {
	return x;
    }

    public void setX(int x) {
	this.x = x;
    }

    public int getY() {
	return y;
    }

    public void setY(int y) {
	this.y = y;
    }
}

例題: ボールのアニメーション(3)

基本図形を描くだけではなく、 外部にある画像ファイルを取り込むこともできます。 下のボールの画像ファイルをダウンロードして、 実行してください。 (BallAnimation3.java)

[ ボールの画像 (ball.png) ]

import java.awt.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;

class BallAnimation3 {
    public static void main(String[] args) {
	JFrame frame = new JFrame();

	frame.setTitle("Ball Animation");
	frame.setSize(640, 480);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	MyPanel panel = new MyPanel();
	frame.getContentPane().add(panel);

	frame.setVisible(true);
    }
}

class MyPanel extends JPanel implements Runnable {
    private Ball ball;

    // イメージオブジェクトを入れる変数
    private Image ballImage;

    public MyPanel() {
	setBackground(Color.white);

	ball = new Ball(100,100,1,1,0,0,580,400);

        // ファイルを読込みイメージオブジェクトを生成
	try {
	    ballImage = ImageIO.read(new File("ball.png"));
	}
	catch(IOException e) {
	    System.out.println("ファイルを読み込めません。");
	}

	Thread refresh = new Thread(this);
	refresh.start();
    }

    public void paintComponent(Graphics g) {
	super.paintComponent(g);

	ball.forward();

        // 座標を指定しイメージオブジェクトを表示
	g.drawImage(ballImage, ball.getX(), ball.getY(), null);
    }

    public void run() {
	while(true) {
	    repaint();
	    try {
		Thread.sleep(10);
	    }
	    catch(Exception e) {
	    }
	}
    }
}

class Ball {
    private int x;
    private int y;
    private int vx;
    private int vy;
    private int left;
    private int right;
    private int top;
    private int bottom;

    public Ball(int x, int y, int vx, int vy, int l, int t, int r, int b) {
	this.x = x;
	this.y = y;
	this.vx = vx;
	this.vy = vy;
	right = r;
	left = l;
	top = t;
	bottom = b;
    }

    public void forward() {
	if (x + vx < left || x + vx > right) 
	    vx = -vx;
	if (y + vy < top || y + vy > bottom) 
	    vy = -vy;
	x = x + vx;
	y = y + vy;
    }

    public int getX() {
	return x;
    }

    public void setX(int x) {
	this.x = x;
    }

    public int getY() {
	return y;
    }

    public void setY(int y) {
	this.y = y;
    }
}

下線で示した部分は、 外部からの画像を読込み表示するために必要な記述です。