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

   2012/04/27

こんちは、管理人イガジーです。

プログラミングでやっかいなのは、人の入力や操作の相手をする部分です。
人それぞれに、好みやこだわりがあり、使う人が増えれば増えるほど、
要求は多様になってきます。
自分専用のプログラムの場合でも、時間が経つと気も変わります。

例えば、年月日を指定する場合を考えてみましょう。
YYYYMMDD と、年(YYYY)を4桁、月(MM)を2桁、日(DD)を2桁、
計8桁の数字(例えば、”20111210″という形)で入力してもらうのが
処理する側(プログラムの作り方)としては簡単です。

ただ、桁は少ない方が入力が楽なので
YYMMDD と、年(YY)を2桁、月(MM)を2桁、日(DD)を2桁、にして
年は20xx年に固定する方法もあります。

20xxに固定するのは、なんとなく融通が効かない気がする場合は
現在の年(今なら2011年)の上位2桁を設定するようにしておけば、
21xx年になっても使えます。
(もちろん、そこまでこだわらなくてもいいだろう、という考えもあります。)

同じ年の場合は年を省略して MMDD の4桁でも受け付けて欲しいですし
さらに、11月に 0123(1月23日)の様に、前の月日を指定したら、
自動的に来年の1月23日にして欲しくなったりします。

(また、年月日は、yy/mm/dd と”/” で区切るものだ
という信念を持った人もいるでしょうし、
mm/dd/yy の順序、あるいは dd/mm/yyの順序がイイ
という人もいると思います。)

では、以下に実際のプログラム例を示します。

まず、main()から、コンストラクタCountDown() に argsを渡すようにします。

CountDown(String [] as) { // constructor
//...略
}
main(String [] args) {
    new CountDown(args);
}

コンストラクタでは、as という変数名にしていますが
何でもかまいません。main と同じ args という名称でも良いのですが
混乱を招く可能性があるので違う名称にしています。

起動時に引数(アーギュメント)を指定しなかった場合、
as[] の要素数はゼロなので、無条件に as[0]を参照すると
例外が発生します(エラーが表示される)。

そこで、まずは as.length で、要素数が0かどうかを判定してから
処理するようにします。

int dyy=cyy+1;
int dmm=0;
int ddd=1;
if (as.length>0) {
// ... 引数があった場合に年月日の処理をする
}
d=new GregorianCalendar(dyy,dmm,ddd);

という感じですね。

当月の残り日数は “-m” と指定することにすると

if (as.length>0) {
// ... 引数があった場合に年月日の処理をする
}

の部分は、

if (as.length>0) {
// ... 引数があった場合に年月日の処理をする
}

の部分は

if (as.length>0) {
  if (as[0].equals("-m")) {
    dyy=cyy;
    dmm=cmm+1;
    if (dmm>11) {++dyy; dmm=0;}
  }else{
// 年月日の数字指定の処理
  }
}

という感じでしょう。
cyyは現在の(実行した時点での)年、cmmは現在の月です。

さて、数字指定の処理です。
まず
int ymd=Integer.parseInt(as[0]);で、数字を得ることができますが、
数字にできない文字列が含まれていた場合に例外が発生するので
try-catch で囲うようにします。

int ymd=0;
try {
  ymd=Integer.parseInt(as[0]);
}catch(Exception e){
  ymd=0;
}
int y0=ymd/10000;
dmm=(ymd%10000)/100 - 1;
ddd=ymd%100;

という形でy0に年、dmmに月、dddに日が得られます。

年を省略した場合、y0 は 0 になるので
その時は dyyにcyy(現在の年)を入れるようにします。
その際、月日が現在の月日よりも前だったら、年(dyy)を +1 します。

年が 0 ではなく、100未満だったら、cyyの上位2桁を補います。
複雑に感じると思いますが、これが人の入力を処理する面倒なところです。
プログラム例は次のような感じです。

if (y0==0) { // 年が省略されていたら
	dyy=cyy; // 現在の年をセット
	if ((dmm*100+ddd)<(cmm*100+cdd)) ++dyy; // 月日が過去だったら年を+1
}else if (y0<100) dyy=(cyy/100)*100+y0; // 年が2桁入力だったら補う

こういった処理の他に
例えば、11月35日や2月30日などと指定されたらどうするか、
とか、9999年などの指定があったらどうするか、
なども気になるかもしれませんね。

意地悪入力を全く考えないのは困りますが、考えすぎるのもよくないのです。
キリがないので、どこかで割り切りが必要になります。

実際に動かしてみると、意地悪入力よりも悩ましい事が起きます。
何かというと、これを表示しっぱなしにしていた場合
日付が変わっても残り日数はそのまま、変化しません。

起動した時に計算して表示して終わり、その後の処理は無いので
当然なのですが、これで良いのか?と悩むわけです。

仕様としては、次のような例が考えられるでしょう。
(aa)一切、更新しないのが仕様だ。と割りきって終わる
(bb)更新ボタンを付けてクリックされたら、計算しなおして再表示する
(cc)フォーカスが当たったら、計算しなおして再表示する
(dd)タイマーを使って、時計の様に更新し続ける

明日は(cc)を考えてみることにします。

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

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

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

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

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