
Java超|スレッドでアニメーションを作る
止まっていた画面に、時間の流れを吹き込む。スレッドを使ったアニメーションを学ぶと、JavaのGUIアプリは「表示する画面」から「動き続ける画面」へ進化します。
これまでのGUIアプリケーションでは、ウィンドウを表示し、部品を配置し、画像を表示し、マウス操作に応じて画面を描き変えるところまで学んできました。
Frame で画面の土台を作る。
Label や Button を置く。
MouseEvent から座標を取得する。
repaint を呼んで画面を描き直す。
paint の中で文字や図形を描く。
ここまで来ると、JavaのGUIアプリはかなり表情豊かになります。
しかし、さらに一歩進むと、ユーザーが操作したときだけではなく、時間の経過に合わせて画面を変化させることができます。
これがアニメーションです。
たとえば、戦士本部の重力修行場に「修行段階」を表示する大きな案内盤があるとします。
最初は、次のように表示されます。
修行段階 0 に到達1秒後に、次のように変わります。
修行段階 1 に到達さらに1秒後に、次のように変わります。
修行段階 2 に到達このように、一定時間ごとに表示内容を更新し、画面を描き直すことで、静止した画面に時間の流れが生まれます。
ドラゴンボール風にたとえると、重力修行場の表示盤が、戦士の気の高まりに合わせて段階をひとつずつ進めていくようなものです。
GokuWarrior が集中を高める。
GohanAnalyzer が修行記録を確認する。
表示盤には「修行段階 0」「修行段階 1」「修行段階 2」と順番に映し出される。
このように、画面が時間に合わせて変化すると、GUIアプリは静かな掲示板ではなく、動きのある修行装置のように見えてきます。
Javaでこのようなアニメーションを作るときに大切になるのが、スレッドです。
スレッドを使うことで、一定間隔で値を更新し、repaint を呼び、少し待って、また値を更新するという流れを作れます。
この記事では、具体的な例示プログラムとして Sample7.java を使い、スレッドでアニメーションを作る基本を、ドラゴンボールの世界観でやわらかく整理していきます。
アニメーションとは何か
アニメーションとは、画面の表示内容を少しずつ変化させ、それを連続して見せることで動いているように見せる仕組みです。
今回のような基本例では、図形を動かすのではなく、表示する数値を一定時間ごとに変化させます。
流れは次のようになります。
| 手順 | 内容 |
|---|---|
| 1 | 表示する値を変える |
| 2 | repaint で再描画を依頼する |
| 3 | paint が呼ばれて画面を描き直す |
| 4 | Thread.sleep で少し待つ |
| 5 | また値を変える |
| 6 | この流れを繰り返す |
この繰り返しによって、画面の表示が時間とともに変化します。
ドラゴンボール風にたとえると、重力修行場の案内盤に表示される「修行段階」が、一定時間ごとに上がっていくイメージです。
| 表示のタイミング | 表示内容 |
|---|---|
| 起動直後 | 修行段階 0 に到達 |
| 約1秒後 | 修行段階 1 に到達 |
| 約2秒後 | 修行段階 2 に到達 |
| 約3秒後 | 修行段階 3 に到達 |
このように、表示される値が少しずつ変わり、それが一定間隔で描き直されることで、画面に時間の流れが生まれます。
なぜスレッドを使うのか
アニメーションでは、画面を1回描いて終わりではありません。
一定の間隔で、何度も画面を描き直す必要があります。
そのためには、次のような処理を繰り返す必要があります。
値を変える
↓
画面を描き直す
↓
少し待つ
↓
また値を変えるこの「時間に沿って繰り返す処理」を担当するために、スレッドを使います。
スレッドを使うと、画面更新のための処理を、独立した流れとして動かせます。
ドラゴンボール風にたとえると、修行表示盤には「表示を更新する係」がついているようなものです。
その係は、1回だけ数字を書いて終わるのではありません。
1秒ごとに修行段階を確認し、表示盤を書き換え続けます。
| Javaの要素 | ドラゴンボール風のイメージ |
|---|---|
| Thread | 時間に沿って動く更新係 |
| run | 更新係が実行する作業内容 |
| repaint | 表示盤に描き直しを依頼する合図 |
| sleep | 次の更新まで一呼吸置く時間 |
| paint | 表示盤に実際の文字を描く係 |
アニメーションは、スレッドだけで完成するわけではありません。
スレッドが時間の流れを作り、値を変え、repaint で描き直しを依頼します。
そして、paint がその時点の値を画面に描きます。
この役割分担が、スレッドを使ったGUIアニメーションの基本です。
図:スレッドでアニメーションを作る全体像

この図が示していること
この図は、スレッドでアニメーションを作る基本構造を表しています。
スレッドは、一定間隔で step の値を更新します。
step の値を変えたあと、repaint を呼んで画面の再描画を依頼します。
その結果、paint が呼ばれ、現在の step の値を使って画面に文字を描きます。
| 図の要素 | 意味 |
|---|---|
| Thread | 時間の流れを作る処理 |
| run | スレッドが実行する処理 |
| step | 表示する修行段階を表す値 |
| repaint | 画面を描き直す依頼 |
| paint | 実際に画面へ描画する処理 |
| Thread.sleep | 次の更新まで待つ処理 |
この図から分かることは、アニメーションは「値の更新」「再描画」「待機」を繰り返すことで成り立つということです。
スレッドを使ったアニメーションの例
ここでは、1秒ごとに修行段階の表示が変わるプログラムを見ていきます。
ファイル名:Sample7.java
import java.awt.*;
import java.awt.event.*;
public class Sample7 extends Frame implements Runnable
{
int step;
public static void main(String[] args)
{
Sample7 sm = new Sample7();
}
public Sample7()
{
super("修行カウント表示");
addWindowListener(new SampleWindowListener());
// 新しいスレッドを開始する
Thread th;
th = new Thread(this);
th.start();
setSize(420, 320);
setVisible(true);
}
public void run()
{
try {
for (int i = 0; i < 10; i++) {
// 表示する段階を更新する
step = i;
// 画面を再描画する
repaint();
// 1秒待つ
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
}
public void paint(Graphics g)
{
g.setFont(new Font("SansSerif", Font.BOLD, 26));
g.drawString("修行段階 " + step + " に到達", 90, 150);
}
class SampleWindowListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
}このプログラムでできること
このプログラムを実行すると、「修行カウント表示」というタイトルのウィンドウが表示されます。
画面の中央付近には、次のような文字が表示されます。
修行段階 0 に到達約1秒後には、表示が次のように変わります。
修行段階 1 に到達さらに約1秒後には、次のように変わります。
修行段階 2 に到達このように、表示が順番に変化していきます。
最終的には、修行段階 9 まで進みます。

このプログラムで行っていることを整理すると、次のようになります。
| できること | 内容 |
|---|---|
| ウィンドウを表示する | Frame を継承して画面を作る |
| スレッドを開始する | Thread を作り start を呼ぶ |
| スレッドで処理を動かす | run の中で繰り返し処理を行う |
| 表示する値を変える | step に 0 から 9 まで代入する |
| 画面を描き直す | repaint を呼ぶ |
| 表示間隔を作る | Thread.sleep(1000) で1秒待つ |
| 文字を描画する | paint の中で drawString を使う |
| 閉じる操作に対応する | WindowAdapter と windowClosing を使う |
ドラゴンボール風にたとえると、戦士本部の修行表示盤が、1秒ごとに修行段階を更新していくアプリです。
GokuWarrior が修行を進めるたびに、表示盤の段階が 0 から 1、1 から 2 へと進んでいくように見えます。
Sample7 は Frame であり Runnable でもある
クラス宣言は次のようになっています。
public class Sample7 extends Frame implements Runnableこの1行には、2つの役割が含まれています。
| 指定 | 役割 |
|---|---|
| extends Frame | ウィンドウとして動けるようにする |
| implements Runnable | スレッドで実行する処理を持てるようにする |
Sample7 は Frame を継承しているため、ウィンドウとして表示できます。
同時に Runnable を実装しているため、run メソッドを持ち、Thread に渡してスレッド処理として動かせます。
ドラゴンボール風にたとえると、Sample7 は「修行表示盤」そのものでありながら、「自分で表示を更新する係」も兼ねています。
| Javaの役割 | ドラゴンボール風のイメージ |
|---|---|
| Frame | 修行表示盤の本体 |
| Runnable | 自動更新の任務を持つ約束 |
| run | 表示更新係が行う作業 |
| Thread | その作業を時間に沿って動かす流れ |
このように、Sample7 は画面としての役割と、アニメーション処理を持つ役割の両方を担当しています。
Runnable を実装する意味
Runnable は、スレッドで動かしたい処理を持たせるためのインターフェイスです。
Runnable を実装するクラスでは、run メソッドを書きます。
public void run()
{
// スレッドで実行したい処理
}今回の Sample7 では、run の中にアニメーションの中心となる処理を書いています。
public void run()
{
try {
for (int i = 0; i < 10; i++) {
step = i;
repaint();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
}つまり、Runnable を実装することで、Sample7 は「スレッドで実行する処理」を持てるようになります。
ただし、Runnable を実装しただけではスレッドは始まりません。
Thread オブジェクトを作り、start を呼ぶ必要があります。
| 段階 | 内容 |
|---|---|
| implements Runnable | スレッドで動かす処理を持つ |
| run を定義する | 実際の処理を書く |
| new Thread(this) | このオブジェクトの run を動かす Thread を作る |
| start を呼ぶ | 新しいスレッドを開始する |
ドラゴンボール風にたとえると、Runnable は「自動更新任務を持つ」という約束です。
しかし、任務内容を持っているだけでは動きません。
Thread という実行係に渡して、start で任務を開始させる必要があります。
Thread を作って start する流れ
コンストラクタの中では、次のようにスレッドを作って開始しています。
Thread th;
th = new Thread(this);
th.start();この3行を分けて見ると、役割が分かりやすくなります。
| コード | 役割 |
|---|---|
| Thread th; | Thread 型の変数を用意する |
| th = new Thread(this); | この Sample7 オブジェクトをもとに Thread を作る |
| th.start(); | スレッドを開始する |
ここで出てくる this は、現在の Sample7 オブジェクト自身を表します。
Sample7 は Runnable を実装しているため、Thread に渡せます。
th = new Thread(this);これは、次のような意味です。
この Sample7 オブジェクトの run を、新しいスレッドで動かしてください。
そして、start を呼びます。
th.start();start が呼ばれると、新しいスレッドが開始され、その中で run が実行されます。
ここで重要なのは、run を直接呼ばないことです。
| 呼び方 | 動き |
|---|---|
| run を直接呼ぶ | 普通のメソッド呼び出しになる |
| start を呼ぶ | 新しいスレッドが始まり、その中で run が動く |
ドラゴンボール風にたとえると、run は任務内容が書かれた巻物です。
start は、その任務を実際に開始する出撃命令です。
巻物を読むだけでは、時間に沿った自動更新は始まりません。
start によって、修行表示盤の自動更新係が動き始めます。
図:Thread を開始して run が動く流れ

この図が示していること
この図は、Sample7 から Thread を作り、start によって run が動き始める流れを表しています。
Sample7 は Runnable を実装しているため、run メソッドを持っています。
コンストラクタで new Thread(this) と書くことで、Sample7 自身を Thread に渡します。
そして th.start を呼ぶと、新しいスレッドが開始され、run の中の処理が実行されます。
| 図の要素 | 意味 |
|---|---|
| Sample7 | ウィンドウ本体であり、Runnable を実装したオブジェクト |
| this | 現在の Sample7 オブジェクト自身 |
| new Thread(this) | Sample7 の run を動かす Thread を作る |
| th.start | 新しいスレッドを開始する |
| run | アニメーションの更新処理を書く場所 |
この図から分かることは、Runnable を実装しただけでは動かず、Thread に渡して start を呼ぶことで初めてスレッド処理が始まるということです。
run でアニメーションの流れを作る
アニメーションの中心になるのが run メソッドです。
public void run()
{
try {
for (int i = 0; i < 10; i++) {
// 表示する段階を更新する
step = i;
// 画面を再描画する
repaint();
// 1秒待つ
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
}この中では、次の3つの処理を繰り返しています。
| 処理 | 内容 |
|---|---|
| step = i | 表示する段階を更新する |
| repaint | 画面を描き直すように依頼する |
| Thread.sleep(1000) | 1秒待つ |
この3つが、アニメーションの基本のリズムです。
値を変える
↓
描き直す
↓
少し待つ
↓
次の値へ進むドラゴンボール風にたとえると、修行表示盤の更新係が次のように動いています。
| 流れ | ドラゴンボール風の動き |
|---|---|
| step = i | 修行段階を記録カードに書く |
| repaint | 表示盤に描き直しを命じる |
| Thread.sleep(1000) | 次の段階まで一呼吸置く |
この流れを繰り返すことで、修行段階が時間とともに進んで見えます。
for 文が修行段階を進める
run の中では、for 文を使っています。
for (int i = 0; i < 10; i++) {この for 文により、i の値は 0 から 9 まで順番に変わります。
| 繰り返し | i の値 | step の値 |
|---|---|---|
| 1回目 | 0 | 0 |
| 2回目 | 1 | 1 |
| 3回目 | 2 | 2 |
| 4回目 | 3 | 3 |
| ... | ... | ... |
| 10回目 | 9 | 9 |
for 文の中で、i を step に代入しています。
step = i;これにより、表示に使う step の値が 0、1、2、3 と進んでいきます。
ドラゴンボール風にたとえると、for 文は修行段階の進行表です。
修行段階 0 から始まり、1、2、3 と順番に上がっていきます。
そのたびに表示盤が描き直されるため、画面上でも段階が進んで見えます。
repaint は画面更新の依頼
step の値を変えただけでは、画面の見た目がすぐに変わるとは限りません。
そこで repaint を呼びます。
repaint();repaint は、画面をもう一度描き直してほしいと依頼するメソッドです。
実際に描画するのは paint です。
| メソッド | 役割 |
|---|---|
| repaint | 再描画を依頼する |
| paint | 実際に画面へ描く |
今回の流れでは、step の値を変えたあとに repaint を呼びます。
step = i;
repaint();これにより、Javaは必要なタイミングで paint を呼び、最新の step の値を画面に描きます。
ドラゴンボール風にたとえると、BulmaSupport が「現在の修行段階は 3 です」と記録カードを更新しただけでは、表示盤の見た目はまだ古いままです。
支援係が「表示盤を描き直してください」と合図を出す必要があります。
その合図が repaint です。
Thread.sleep で表示の間隔を作る
run の中では、repaint のあとに Thread.sleep を呼んでいます。
Thread.sleep(1000);1000 はミリ秒です。
つまり、Thread.sleep(1000) は、現在のスレッドを約1秒間一時停止するという意味です。
| 指定 | 待つ時間 |
|---|---|
| 500 | 0.5秒 |
| 1000 | 1秒 |
| 2000 | 2秒 |
この待ち時間があることで、表示の変化が見やすくなります。
もし Thread.sleep(1000) がなければ、for 文は一瞬で進み、0 から 9 までの変化がほとんど見えません。
アニメーションとして見せるには、変化の間に時間差が必要です。
ドラゴンボール風にたとえると、修行段階を一瞬で 0 から 9 まで進めてしまうと、戦士は何が起きたのか分かりません。
1段階ごとに一呼吸置くことで、修行の進み方が見えるようになります。
InterruptedException に備える
Thread.sleep を使うときは、InterruptedException に備える必要があります。
そのため、run の中では try-catch を使っています。
try {
for (int i = 0; i < 10; i++) {
step = i;
repaint();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}InterruptedException は、スレッドが待機中に割り込みを受ける可能性があるために扱う例外です。
学習段階では、まず次のように理解すると分かりやすいです。
| 要素 | 内容 |
|---|---|
| Thread.sleep | スレッドを一定時間待たせる |
| InterruptedException | 待っている途中で割り込みが起きる可能性に備える例外 |
| try-catch | その可能性に対応するための書き方 |
ドラゴンボール風にたとえると、更新係が1秒休んでいる間に、急な通信が届く可能性に備えているようなものです。
paint で現在の step を描画する
画面に実際の文字を描いているのは paint メソッドです。
public void paint(Graphics g)
{
g.setFont(new Font("SansSerif", Font.BOLD, 26));
g.drawString("修行段階 " + step + " に到達", 90, 150);
}この中では、まずフォントを設定しています。
g.setFont(new Font("SansSerif", Font.BOLD, 26));これは、SansSerif の太字、26ポイントの文字で描くという意味です。
次に、drawString で文字列を描いています。
g.drawString("修行段階 " + step + " に到達", 90, 150);ここで step の値が文字列に組み込まれています。
| step の値 | 画面に表示される文字 |
|---|---|
| 0 | 修行段階 0 に到達 |
| 1 | 修行段階 1 に到達 |
| 2 | 修行段階 2 に到達 |
| 9 | 修行段階 9 に到達 |
paint は、呼ばれた時点の step の値を見て描画します。
つまり、run が step を更新し、repaint が paint を呼び、paint が現在の step を画面に表示する、という流れです。
スレッドと描画の役割分担
ここで大切なのは、スレッドが直接画面に文字を描いているわけではないことです。
スレッドの役割は、時間の流れを作り、step を更新し、repaint を呼ぶことです。
実際の描画は paint が担当します。
| 役割 | 担当 |
|---|---|
| 時間の流れを作る | Thread |
| 表示する値を変える | run |
| 画面更新を依頼する | repaint |
| 実際に描画する | paint |
| 表示間隔を作る | Thread.sleep |
この分担が分かると、アニメーションの構造が整理しやすくなります。
ドラゴンボール風にたとえると、次のようになります。
| Javaの処理 | ドラゴンボール風の役割 |
|---|---|
| Thread | 修行の時間管理係 |
| run | 段階更新の任務内容 |
| step | 現在の修行段階 |
| repaint | 表示盤への描き直し命令 |
| paint | 表示盤に文字を書く係 |
| sleep | 次の段階までの待機時間 |
スレッドは、表示を更新するためのきっかけを作ります。
paint は、そのきっかけを受けて、現在の状態を画面に描きます。
図:アニメーションが成立する仕組み

この図が示していること
この図は、アニメーションが成立する理由を表しています。
アニメーションは、1回だけ描画して終わるものではありません。
step を更新し、repaint で再描画を依頼し、paint が現在の step を描き、Thread.sleep で一定時間待つ。
この流れを繰り返すことで、画面の表示が少しずつ変化して見えます。
| 図の要素 | 意味 |
|---|---|
| stepを更新 | 表示する内容を変える |
| repaint | 画面を描き直すように依頼する |
| paint | 現在の状態を画面に描く |
| Thread.sleep | 次の表示まで間隔を作る |
| ループ | この流れを繰り返す |
この図から分かることは、アニメーションは「値の変化」「再描画」「待機時間」の3つが組み合わさって成立するということです。
アニメーションが成立する理由
今回のプログラムでアニメーションらしく見える理由は、次の3つがそろっているからです。
| 必要な要素 | 内容 |
|---|---|
| 表示内容が変わる | step が 0 から 9 まで変化する |
| 毎回描き直す | repaint によって paint が呼ばれる |
| 変化の間隔がある | Thread.sleep(1000) で約1秒待つ |
この3つのうち、どれかが欠けると、アニメーションとして見えにくくなります。
たとえば、step を変えなければ、毎回同じ文字が表示されます。
repaint を呼ばなければ、値が変わっても画面に反映されにくくなります。
Thread.sleep がなければ、変化が一瞬で終わってしまい、ユーザーには流れとして見えにくくなります。
| 欠けているもの | 起こりやすいこと |
|---|---|
| step の更新 | 画面の内容が変わらない |
| repaint | 画面が更新されない |
| Thread.sleep | 一瞬で終わって変化が見えにくい |
ドラゴンボール風にたとえると、修行段階を変える記録、表示盤への描き直し命令、次の段階までの一呼吸。
この3つがそろって、修行の進行が画面に表れます。
もっと発展させると何ができるか
今回のプログラムでは、文字の中の数字を変えるだけのシンプルなアニメーションを作っています。
しかし、この考え方を広げると、さまざまな動きに応用できます。
| 応用例 | できること |
|---|---|
| 位置を変える | 図形や画像を横に動かす |
| 色を変える | 一定時間ごとに色を切り替える |
| サイズを変える | 気のしるしが大きくなる表現を作る |
| 複数の値を使う | 位置、色、大きさを同時に変える |
| 画像を切り替える | 戦士アイコンの動きのように見せる |
| メーターを増やす | 修行ゲージが上がる表現を作る |
たとえば、step の値を文字表示だけでなく、図形の位置に使うこともできます。
g.fillOval(50 + step * 20, 150, 30, 30);このようにすれば、step が増えるたびに丸が右へ動いていきます。
ドラゴンボール風にたとえると、修行段階が進むたびに、気のしるしが表示盤の上を少しずつ移動していくような表現です。
はじめて学ぶときに押さえたい見方
スレッドと描画が同時に出てくると、最初は少し複雑に見えるかもしれません。
そのときは、次の4つに分けて考えると分かりやすくなります。
| 見る場所 | 確認すること |
|---|---|
| 時間の流れを作る場所 | run と Thread.sleep |
| 値を変える場所 | for 文の中の step = i |
| 画面更新を依頼する場所 | repaint |
| 実際に描く場所 | paint と drawString |
特に大切なのは、run と paint の役割を混同しないことです。
| メソッド | 役割 |
|---|---|
| run | 時間に沿って値を変え、repaintを呼ぶ |
| paint | 現在の値を使って画面を描く |
run はアニメーションの進行役です。
paint は画面表示の担当です。
repaint は、その2つをつなぐ合図です。
ドラゴンボール風にたとえると、run は修行段階を進める記録係、paint は表示盤にその段階を書く描画係、repaint は「表示を更新してください」という通信札です。
この内容でつかんでおきたいこと
今回のテーマでいちばん大切なのは、スレッドを使うことで、一定時間ごとに画面を更新できるということです。
ただし、スレッドだけで画面を描くわけではありません。
スレッドが値を変え、repaint で再描画を依頼し、paint が画面に描きます。
| ポイント | 内容 |
|---|---|
| Runnable | スレッドで動かす処理を持たせるための仕組み |
| Thread | 新しく動く処理の流れを作る |
| start | スレッドを開始する |
| run | スレッドで実行する処理を書く |
| step | 表示する修行段階を保存する |
| for 文 | step を 0 から 9 まで進める |
| repaint | 画面の再描画を依頼する |
| paint | 実際に画面を描く |
| drawString | 文字列を描画する |
| Thread.sleep | 表示の間隔を作る |
| InterruptedException | sleep 中の割り込みに備える例外 |
この流れがつかめると、JavaのGUIは「押したら変わる画面」だけではなく、「時間とともに動く画面」として見えてきます。
ドラゴンボール風にたとえると、修行表示盤はもう静かな掲示板ではありません。
時間の流れに合わせて修行段階を進め、1秒ごとに表示を更新し、戦士の成長を映し出す生きた修行装置になります。
