前置きが、すっかり長くなってしまいました。今回は「時計の基礎」
です。アナログの時計は、どうしてもグラフィックスを使わなくてはならず
ボツ。デジタルなら何とかできるでしょう。(また行き当たりばったりで
作ってみます。)
まずは、今の時間はどうやって調べたらいいのでしょう。
#include <time.h> time_t time(time_t *timer); #include <time.h> struct tm *localtime(const time_t *timer); #include <time.h> char *asctime(const struct tm *timeptr);最初のtime()関数ですがこれは、もう第13章で出てきました。 1970年1月1日の0時0分0秒からの経過時間を返す関数ですね。time_tというのも すでに13章で説明済みです。忘れた人は、もう一度13章を読んでください。
次のlocaltime()関数は何をするのでしょうか。これは、time関数で得られた経過時間を 地方時間に直すものです。time関数で得られる経過時間は世界標準時間での話なので 日本時間に直す必要があるわけです。では、この関数の戻り値は一体なんでしょう? struct tmというのは、もうすでに定義されていてVC++1.51のヘルプによると次のような メンバを持ちます。
メンバー 内 容 int tm_sec 秒 int tm_min 分 int tm_hour 時間(0〜24) int tm_mday 日付(1〜31) int tm_mon 月(0〜11、1月を0とする) int tm_year 年(現在の年から1900を引いた値) int tm_wday 曜日(0〜6、日曜日を0とする) int tm_yday 年初からの通算日数(0〜365、1月1日を0とする) int tm_isdst 夏時間が有効な場合には0以外、それ以外の場合には0この意味の分からない人は、第15章を参照してください。
そして、最後にasctime()関数は、localtime()関数で得られたtm構造体より、文字列を 作り出す関数と思えばよいでしょう。
この説明は、少々正しくないところがあるが・・・手順1 time関数で経過時間を取得する time(経過時間へのポインター); 手順2 localtime関数で地方時間に直す tm構造体へのポインター=localtime(経過時間へのポインター); 手順3 tm構造体から文字列を得る 文字型へのポインター=asctime(tm構造体へのポインター);
コメントと、上の「手順」を見比べながらじっくり見てください。
構造体へのポインターは、あとの章でまた出てきます。
現在の日付・時刻が表示されましたね。こうなれば大成功です。
今回使った3つの関数は、どんなコンパイラでもOK(の筈です)。
あー、基本的にはそうですが少し違います。 これをグルグル回しにしたらどうなるかやってみましょう。 time(&present_tm);からprintf(...)までを while(1){ }で囲んでしまうと・・・
確かに、現在の日付と時刻を表示し続けますが、
第一やめることができない。(ストップキーを押すしかない)
また、表示する場所が次々と新しいところに移っている。
等々の問題点があります。(超初心者にありがち)
ではどうすればよいのでしょう。マイクロソフトの コンパイラでは、
というのがあって、rowとcolumnに数値を入れれば、その テキスト座標に表示することができます。 しかし、これはANSIに準拠していません。 文字に色を付けたり、カーソルを移動させたりする命令は、 ハードウェアに依存しています。ですから、 この手の関数はANSIで認めていないのです。#include <graph.h> struct _rccoord __far _settextposition(short row,short column);
自分の持っているコンパイラが、どんな関数でこれを実現しているのか 調べてみてください。ここでは、もう少し別な方法を考えてみましょう。
ESC [ps; ps; ps;.....;ps m
ps | 属性 | ps | 属性 |
0 | デフォルト | 30(40) | 黒 |
1 | ハイライト | 31(41) | 赤 |
2 | 垂線表示 | 32(42) | 緑 |
4 | アンダーライン | 33(43) | 黄 |
5 | ブリンク | 34(44) | 青 |
7 | リバース | 35(45) | 紫 |
8 | シークレット | 36(46) | 水色 |
37(47) | 白 |
さて、具体的な使い方ですが、まず(ESC)を出力します。 それに続いて、[を出力、その後ps(表を参照)mの順に出力します。 psは、複数書いてかまいません。ESCの出力の仕方は、いろいろ考えられます。
printf("\x1b");
putchar(0x1b);
printf("%c", 0x1b);
などなど使いやすいように工夫してみてください。
エスケープ・シーケンスをいろいろな方法で書いてみました。
みなさんもいろいろな書き方を考えてみてください。
カラフルできれいですね。
次は、カーソル移動の説明です。
ESC [pl;pcH
plがy座標、pcがx座標を表します。xとyを間違えないでください。
printf("\x1b[12;10H");
とすればカーソルは、(10,12)に移動します。 これで、何とか時計らしきものが作れそうですね。 あとは、ループからの脱出方法です。 これには、よく
kbhit()関数
が使われます。
この関数はANSIで認められていませんが、たいていの
処理系で使えます。キーボードから何も入力がなければ
0を返し、何か入力があると0以外を返します。
while(!kbhit())の使い方は是非マスターしてください。
まあ、何とか目的は達成しています。しかし不満は残ります。 実際動かしてみるとわかるのですが、カーソルがうるさい、 画面がチカチカするなどです。カーソルを消すには、やはり エスケープ・シーケンスを使います。
ESC [>5h
で消えます。
ESC [>5l
で出現します。チカチカするのを止めるのは、非常に速い
速度で書き直しているからです。得られた文字列を
いったん何かに蓄えておいて、次に得られた文字列と比較します。
同じであれば何もせず、違っていれば書き直しこの文字列を
またどこかに蓄えておく、という作業をすればチカチカしなくなります。
ぜひ、このプログラムに挑戦してみてください。
今までの章を完全にマスターしていれば簡単にできるはずです。
Update Nov/18/1996 By Y.Kumei