countdownプログラムを作ってみよう6
こんにちは、管理人イガジーです。
最近のパソコンは高性能になっているので、少々無駄があるプログラムでも
ガンガン平気で動かすことができます。
Javaも昔は「重い」「遅い」と言われていましたが、Java自体の改良と
パソコンの高性能化のおかげで、軽々と動くようになりました。
速くではなく早く、つまり開発に時間をかけずに動かすため、あるいは
バグを生みにくくするために、少しくらいの無駄は気にしないというのが
最近の主流の考え方のようです。
管理人イガジーとしては、まずは無駄があっても、確実に動くものを作り
その後で、チューンナップ(無駄を削減し効率化)するのが良いと思っています。
(往々にして、チューンナップの方が時間がかかったりしますが)
さて、今日は、タイマーを使ってカウントダウンを自動更新するようにしてみましょう。
時計の描画のような周期的な処理をするには、
Timer クラスと TimerTask クラスを使います。
使い方は、次のようになります。
Timer tmr=new Timer();
tmr.schedule(new MyExtTimerTask(), 開始までの待ち時間(ms), 周期(ms));
...
class MyExtTimerTask extends TimerTask {
public void run() {
// ここに周期的に行う処理を書く
}
}
ここで、”MyExtTimerTask” の部分は好きな名称にしてください。
このタイマー処理を止めるには
tmr.cancel();
とします。
開始までの待ち時間は、1000(ms=1秒)くらいが良いでしょう。
周期は、あまり短いと無駄ですし、長いとそのぶん、日付が変わった時に
反映されるのに時間がかかります。
カウントダウンで秒まで表示する場合は、1000(以下)にします。
まずは、日にちの下に残り時間を時分秒で表示してみましょう。
既にBorderLayoutでの辺+中央は全て使っているので
下辺(SOUTH)にPanelを置いて、2つのラベルを格納します。
具体的にプログラム例を示しましょう。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;
public class CountDown {
Calendar c,d;
int cyy,cmm,cdd;
int dbk=-1;
long cms,dms;
Timer tmr;
Font f1=new Font("SansSerif",Font.PLAIN,20);
Font f2=new Font("SansSerif",Font.PLAIN,16);
Font f3=new Font("SansSerif",Font.PLAIN,72);
Label today=new Label();
Label rest=new Label();
Label restime=new Label();
CountDown(String [] as) { // constructor
Frame f=new Frame();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent ev) {
System.exit(0);
}
});
f.setSize(300,200);
f.setTitle("CountDown");
today.setFont(f2);
today.setAlignment(Label.CENTER);
// f.add(today, BorderLayout.SOUTH);
Panel p2=new Panel();
p2.setLayout(new GridLayout(2,1));
restime.setFont(f1);
restime.setAlignment(Label.CENTER);
p2.add(restime);
p2.add(today);
f.add(p2, BorderLayout.SOUTH);
Label target=new Label();
target.setFont(f1);
target.setAlignment(Label.CENTER);
f.add(target, BorderLayout.NORTH);
Label ll=new Label("あと");
ll.setFont(f1);
// ll.setAlignment(Label.RIGHT);
f.add(ll, BorderLayout.WEST);
f.add(target, BorderLayout.NORTH);
Label rr=new Label("日");
rr.setFont(f1);
f.add(rr, BorderLayout.EAST);
rest.setFont(f3);
rest.setAlignment(Label.CENTER);
f.add(rest, BorderLayout.CENTER);
nowday();
int dyy=cyy+1;
int dmm=0;
int ddd=1;
if (as.length>0) {
if (as[0].equals("-m")) {
dyy=cyy;
dmm=cmm+1;
if (dmm>11) {++dyy; dmm=0;}
}else{
char c=as[0].charAt(0);
int ymd=0;
if ((c>='0')&&(c<='9')) {
try {
ymd=Integer.parseInt(as[0]);
}catch(Exception e){
ymd=0;
}
if (ymd!=0) {
int y0=ymd/10000;
dmm=(ymd%10000)/100 - 1;
ddd=ymd%100;
if (y0==0) {
dyy=cyy;
if ((dmm*100+ddd)<(cmm*100+cdd)) ++dyy;
}
else if (y0<100) dyy=(cyy/100)*100+y0;
else if (y0>=cyy) dyy=y0;
}
} // end if a number is given
}
}
d=new GregorianCalendar(dyy,dmm,ddd);
upcount();
if (as.length==0) target.setText("今年は");
else if (as[0].equals("-m")) target.setText("今月は");
else target.setText(String.format("%d年 %d月 %d日まで",
d.get(Calendar.YEAR),
d.get(Calendar.MONTH)+1,
d.get(Calendar.DAY_OF_MONTH)));
tmr=new Timer();
tmr.schedule(new DoCount(), 1000, 1000);
// tmr.schedule(new DoCount(), 1000, 1000*60);
f.setVisible(true);
} // end of constructor
void nowday(){
c=new GregorianCalendar();
cyy=c.get(Calendar.YEAR);
cmm =c.get(Calendar.MONTH);
cdd =c.get(Calendar.DAY_OF_MONTH);
cms=c.getTimeInMillis();
String td=String.format("今日は %d年 %d月 %d日", cyy,cmm+1,cdd);
today.setText(td);
}
void upcount(){
dms=d.getTimeInMillis();
int st=(int)((dms-cms)/1000); //秒
int mm=st/60; //分
int hh=mm/60; //時(hour)
int dd=hh/24; //日
int ss=st%60;
mm= mm%60;
hh= hh%24;
if (dd!=dbk) {
String rd=Integer.toString(dd);
rest.setText(rd);
dbk=dd;
if (st>0) rest.setBackground(Color.YELLOW);
else rest.setBackground(Color.RED);
}
restime.setText(String.format("%d時間%2d分%2d秒", hh,mm,ss));
// restime.setText(String.format("%d時間%2d分", hh,mm));
}
class DoCount extends TimerTask {
public void run() {
nowday();
upcount();
}
}
public static void main(String[] args) {
new CountDown(args);
}
}
この中で、
if (dd!=dbk) { ...}
の部分は「日付が変化した時だけ描画する」という最適化処理です。
条件判断(if)をはずして、無条件に実行させても問題は無いのですが、
毎回描画しなおすのでチラツキが見えるかもしれません。
秒まで描画すると、落ち着かないという場合は
// tmr.schedule(new DoCount(), 1000, 1000); tmr.schedule(new DoCount(), 1000, 1000*60);
// restime.setText(String.format("%d時間%2d分%2d秒", hh,mm,ss)); restime.setText(String.format("%d時間%2d分", hh,mm));
とすれば良いでしょう。
概ねこれで完成ですが、人それぞれ好みがあると思いますので
色々と改造してみてください。
ご意見、ご質問などございましたら、コメントまたは
メールフォームをご利用ください。
ここまでのソースコードや実行プログラム(jar)は、リクエストがあれば
まとめてダウンロードできるようにしようと思っています。
countdownプログラムを作ってみよう1
countdownプログラムを作ってみよう2
countdownプログラムを作ってみよう3
countdownプログラムを作ってみよう4
countdownプログラムを作ってみよう5
countdownプログラムを作ってみよう6(この記事)
この記事へのコメントはこちら