countdownプログラムを作ってみよう5

   2012/05/05

こんにちは、当サイト管理人のイガジーです。

ものには順序というものがあります。例えば、調理においては、
(1)(タマネギの)皮を剥く
(2)刻む
(3)炒める
という順序が普通です。
この順序を入れ替えると思うような料理ができません。

プログラムもしかり。
例えば、昨日の年月日指定の処理をする際には、
事前に今現在の年月日を得ておく必要があります。
年の入力が省略された時に、今現在の年で補ったりするためです。
(頑張れば逆順でもできなくはありませんけれど、面倒です)

一旦作ったプログラムに、機能を追加しようとした際に
処理の順序を大幅に変更しなければならなくなるのはよくある話です。
順序の入替えをすると、バグが出てくる(動きが変になる)のもよくある話ですね。

さて、昨日までのカウントダウンプログラムに
残り日数を再計算する機能を追加してみましょう。
表示したままにしていて、日付が変わった時に対応するためです。

再計算に必要な処理を抜き出すと
今現在の年月日を取得する処理の

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);


残り日数を計算して表示する処理である

d=new GregorianCalendar(dyy,dmm,ddd);
long mst=d.getTimeInMillis()-ms;
int hh=(int)(mst/MS2HOUR);
int dd=hh/24;
String rd=Integer.toString(dd);
Label rest=new Label(rd);

の2箇所です。

それ以外の部分、例えば

rest.setFont(new Font("SansSerif",Font.PLAIN,72));
rest.setAlignment(Label.CENTER);

などは、再実行する必要はありません。
(実行させた際の見た目には同じですが、無駄な処理になります。)

上記の「今現在の年月日を取得する処理」と
「残り日数を計算して表示する処理」を「何かのトリガ」で
実行させるのですが、今日はフォーカスをトリガにしてみます。

フォーカス(focus)が当たった時に処理をするには、focusListenerというものを
対象のコンポーネント(今回の場合はFrame f)に登録します。

f.addFocusListener(new FocusAdapter() {
	public void focusGained(FocusEvent e) {
// ここにフォーカスが当たったときの処理を書く
	}
});

FocusAdapter()が登場してきていますが、Listenerの親戚なので
細かいことは気にしないでください。

// ここにフォーカスが当たったときの処理を書くに、上記の「今現在の年月日を取得する処理」と
「残り日数を計算して表示する処理」を書けば良いわけです。

注意点としては、このfocusListener(FocusAdapter)は、
コンストラクタの外での処理になりますから、使用する変数(cyyやcmm)は
コンストラクタの外(=フィールド)に置いておく必要があります。

昨日の年月日指定処理とあわせて、プログラム例を示します。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Label;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class CountDown {
	final long MS2HOUR=1000*60*60;
	Calendar c,d;
	int cyy,cmm,cdd;
	long cms,dms;

	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();

	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);

		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)));

		f.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent e) {
				nowday();
				upcount();
			}
		});

		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);
//		System.out.println("Update "+td);
	}

	void upcount(){
		dms=d.getTimeInMillis();
		long mst=dms-cms;
		int hh=(int)(mst/MS2HOUR);
		int dd=hh/24;
		String rd=Integer.toString(dd);
		rest.setText(rd);

		if (mst>0) rest.setBackground(Color.YELLOW);
		else rest.setBackground(Color.RED);
//		System.out.println("setcount "+rd+"日と "+Integer.toString(hh%24)+"時間");
	}

	public static void main(String[] args) {
		new CountDown(args);
	}
}

フォーカスが気に入らない人は、更新ボタンを置いても良いでしょう。
しかし実際に使ってみると、操作しないと更新されないというのに
不満を感じるかもしれません。

明日は、タイマーを使って、操作しなくても更新されるようにしてみましょう。

countdownプログラムを作ってみよう1
countdownプログラムを作ってみよう2
countdownプログラムを作ってみよう3
countdownプログラムを作ってみよう4
countdownプログラムを作ってみよう5(この記事)
countdownプログラムを作ってみよう6

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)