スレッドの制御

ファイルはzipフォルダに納められています。
解凍ソフト(Aladdin Expander等)を使って解凍して下さい。

スレッドのスタート

スレッドのスタートをコンストラクタで行うと、プログラムの開始と共にスレッドも開始します。
ボタンが押された時等、開始したいタイミングでスレッドをインスタンス化し、スタート出来ます。

Vectorクラス

Vectorクラスは、可変長の配列を実現するクラスです。
配列は、配列要素数が固定ですが、Vectorクラスでは要素を追加したり削除したりする度に、其のサイズを変化させます。

�@インスタンス化

空のVectorクラスのオブジェクトを作ります。

例: Vector t = new Vector();

�Aオブジェクトの追加

オブジェクトを1つ追加します。

例: t.addElement(obj); //obj:要素(オブジェクト)1つ

�Bオブジェクトの削除

指定番目のオブジェクトを1つ削除します。

例: t.removeElement(i); //「i」番目のオブジェクト削除

�C要素数の取得

現在登録されているオブジェクトの要素数を返します。

例: int n = t.size();

�Dオブジェクトの取り出し

指定番目のオブジェクトを返します。

例: Object obj = (Object)t.get(i); //「i」番目のオブジェクトを取り出す

乱数の利用

個々のスレッドに必要な情報を全て持たせる事で、同じスレッドクラスのオブジェクトでありながら、別々の動きをさせられます。
此処では、乱数を利用して、「1回に移動する量」「y座標」「寝ている時間」を別々に設定します。

スレッドの停止

スレッドを停止させるには、runメソッドを終了させます。
此迄は、runメソッドに、

while(true){
        スレッドの処理
                
}

と書かれていて、プログラムが終了する迄永久に実行を続けていました。
此処にboolean型の変数「flag」を用意し、スタート時は「true」でストップ時に「false」にします。
runメソッドでは、「flag」が「true」の間はループを続ける様にし、「false」になった場合にスレッドを停止する様にします。

while(flag){
        スレッドの処理
                
}

runメソッドは1度終了すると、同じオブジェクトから再び呼び出せません。
其処で、runメソッドが終了したThreadオブジェクトは破棄します。
オブジェクトを破棄するには、Threadクラスのオブジェクト名に「null」を代入します。
つまり、どのオブジェクトも指さない状態にする事でオブジェクトを切り離し、破棄するのです。

スレッドの再起動

スレッドを再起動するには、新しいオブジェクトを作り直し、其の新しいオブジェクトをターゲットにstartメソッドを呼び出す事で、runメソッドを開始します。
従って、Threadオブジェクトが全ての情報を持っていると、停止と同時にオブジェクトが破棄されるので、途中からの再スタートが出来ません。
再スタートに必要な情報(此処では、停止した時の画像番号)は、スレッドではなく制御側に持たせます。

プログラムの設計

�@画像を用意

一定時間で変化する様な、同じ大きさの画像を複数枚用意し、ファイル名が連番になる様に決めておきます。
此処では、下の図の様な画像を用意しました。

img100.gif img123.gif

�A画像の構成を考える

画面には、画像を表示する領域の他に、「開始」「停止」「リセット」ボタンを表示する領域が必要です。
此等のボタンを別のパネルに載せる事にしましょう。
BorderLayoutを配置して、「CENTER」に画像を描き、「SOUTH」にボタンを載せます。

�B画像の動きを決める

プログラム起動時には最初の画像を表示し、開始ボタンが押されたら動き出す様にします。
つまり、スレッドがスタートするのは、開始ボタンによってアクションが起きた時です。
200m秒毎に順に画像を差し替え、全部の画像を表示し終えた所で、スレッドは終了し、最後の画像を表示して止まります。
途中、停止ボタンが押されると動きは停止しますが、開始ボタンで止まった所から再開する様にしましょう。
リセットボタンが押された時は、最初の画像を表示して停止します。

アクションの設定

プログラム起動
最初の画像を表示
開始ボタンを押す
動き出す 全部の画像の表示を終了後、停止
停止ボタンを押した後、開始ボタンを押す
停止 開始ボタンで停止した時の画像の続きを表示
リセットボタンを押す
最初の画像を表示

�Cクラスの構成を決める

クラスは、下の表の構成にします。

クラス名 クラスの役割 内容
Weather フレーム メインのクラス
「BorderLayout」でパネルを配置
WeatherPanel 画像を表示するパネル フレームの「CENTER」に配置
ButtonPanel ボタンを表示するパネル フレームの「SOUTH」に配置
「FlowLayout」で開始ボタン・停止ボタン・リセットボタンを配置
WeatherThread 画像を差し替えるスレッド 一定時間毎に次の画像に切替、「WeatherPanel」に再描画を要求
全部の画像を表示し終えるか、又はスレッドの継続を管理する「flag」を「false」になった時、runメソッドを終了
StartButton スタートボタン 開始ボタンが押された時は、スレッドをインスタンス化してスタート
StopButton ストップボタン 停止ボタンを押された時は、スレッドの継続を管理する「flag」を「false」にし、スレッドを破棄
ResetButton リセットボタン リセットボタンが押された時は、スレッドの継続を管理する「flag」を「を「false」にし、スレッドを破棄、画像番号を「0番」に戻す

�D変数を決める

プログラムを制御する為には、重要な変数が幾つか必要です。

型 変数名 意味 説明
WeatherThread t スレッド 初期値は「null」
開始ボタンでインスタンス化
停止ボタン・リセットボタン又は表示終了で「null」
boolean flag true:スレッド稼働中
false:スレッド停止中
初期値は「false」
開始ボタンで「true」
停止ボタン又は表示終了で「null」
Image[] img 画像 24枚の画像をImageクラスのオブジェクトに変換し、其れを収める配列
Weatherクラス(フレーム)のコンストラクタで全ての画像を変換
int imgNo 画像番号 現在表示している画像配列「img」の添字

日付と時刻の取り扱い

日付や時刻は、Dateクラスで扱います。
マシンに設定されている現在時刻を取得するには、下記のメソッドを使います。

今日の日付と現在時刻の取得

Date オブジェクト名 = Calendar.getInstance().getTime();

日付データの変換

西暦の日付や24時間制の時刻等の様に、表示させたい形式の文字列に変換するには、SimpleDateFormatクラスを使います。
形式を指定したSimpleDateFormatクラスのオブジェクトをターゲットに、変換したいデータを引数にして、formatメソッドを呼び出します。

例: SimpleDateFormat dateFormat = new SimpleDateFormat("yyy.MM.dd'('E')'");
String s = dateFormat.format(date);

上の例の「"yyy.MM.dd'(E')'"」は、変換の形式を示しています。
此の中、「'」で囲まれた文字は、其の侭其の文字を出力します。
其の他の記号については、下の表を参照して下さい。

主な変換記号

文字 意味 例
G 紀元 AD
yyyy 年 2006
MM 月 06
dd 日 24
E 曜日 土
HH 時(24時間制) 13
hh 時(12時間制) 01
mm 分 30
ss 秒 33
a 午前 午後PM

「時」「分」「秒」の取り出し

Dateクラスのオブジェクトから「時」「分」「秒」を取り出すには、Calenderクラスに変換して、以下の様に行います。

Calender.getInstance().get(Calender.取り出す要素指定)

取り出す要素の指定は、Calenderクラスの定数で指定します。
主な物は下の表の通りです。

定数 意味
SECOND 秒
MINUTE 分
HOUR 12時間制の時
HOUR_OF_DAY 24時間制の時
YEAR 年
MONTH 月
DATE 日
DAY 曜日

「秒針」「長針」「短針」の描き方

秒針の終点の座標は3時の方角を「0」として、其処からの角度を「radian」、針の中心を「(x0, y0)」、半径を「r0」とすると、

xe = r0*cos(radian)+x0;
ye = r0*sin(radian)+y0;

秒針の始点の座標は、

xs = r0*0.4*cos(radian)+x0;
ys = r0*0.4*sin(radian)+y0;

秒針を描くには、

g2.drawLine(xs, ys, xe, ye);

針の12時の方向に対する角度は、以下の様に求めます。

秒針
1秒間で6度動くので「sec秒」では、sec*6
長針
1秒間で6度動き、10秒で1度動くので「min分sec秒」では、min*6+sec/10
短針
1時間で30度動き、2分で1度動くので「hour時min分」では、hour*30+min/2

此を3時の方向を「0」としたラジアンに変換するには、

radian = 2*3.14/360*(度-90);

終了ボタンによるプログラムの終了

プログラムを終了するには、以下の様に書きます。

System.exit(0);

此迄にも、フレームのコンストラクタの中で×ボタンが押された時の処理として、毎回描いていた物ですね。

画面の構成

フレームは、「BorderLayout」で「CENTER」に時計表示パネルを配置し、「EAST」にボタンパネルを配置します。
時計表示パネルは、3行1列の「GridLayout」にし、それぞれに1つずつラベルを配置します。
ボタンラベルは縦の「BoxLayout」にし、ボタンを配置します。

プログラムの動き

プログラムの起動と共に時計は動きます。
0.1秒おきに現在の時刻を取得して、其の結果を表示します。
日付と時刻は、ラベルが割り当ててあり、ラベルの文字列を変更する事で表示を更新出来ます。
時計パネルのpaintComponentメソッドは何もしていないので、再描画を要求する必要は有りません。
ラベルの文字の変更は以下の様に行います。

ラベルオブジェクト.setText(表示したい文字列);

停止ボタンが押されると、スレッドを終了して時刻の更新を辞め、「只今停止中」に変更します。
開始ボタンが押されると新たにスレッドをインスタンス化して、スタートします。
表示を「只今稼働中」に戻します。

ソース ダウンロード
MusiThreadSwing.java Thread03.zip Weather01.zip
Weather.java
Weather02.zip
Watch.java

戻る