時計アプリの実装

 

Step-1

とりあえず、円形のウィンドウを表示してみよう。ビットマップの読み込み&メモリに展開する部分は、本編のアプリ「gview」で使用したツールを流用すれば早いかなと。ありがたや〜。そして、透明色を利用すれば、非矩形ウィンドウが表示できるのは本編で学習済だ。ウィンドウにメモリ上のビットをコピーするAPIを作成して・・・ビットマップも埋め込んでイメージ作成。実行えいっ・・・し〜ん。あぅ、真っ黒。しばし沈黙が続いた後、フフフ、API側で受け取るアプリのメモリのアドレスにDSのベースアドレス足すの忘れてたゼ。そして何事もなかったかの様に再度イメージを作成して実行・・・わ〜い表示された。よかったよかった。

 

Step-1

やった〜表示できた。でも、マウスでゴリゴリ・・・。

 


Step-2

Step-1では、ビットマップが表示できたので満足して終わってしまったが、このウィンドウ表示にはちょっとした欠陥がある。ウィンドウを表示した時点では、透明色部分が透過されていないのだ。ウィンドウを移動するか、マウスカーソルでゴリゴリ削ると(やらないと思うけど)透過されるのだが、このままではなんとも具合が悪いのでなんとかしたいなと。そこで考えたのは、移動すれば直るので、(論理的に)移動しちゃえ作戦だ。ウィンドウリフレッシュAPIを呼び出したときに、現在の位置に移動、という仕組みにしてみた。これならマップも更新されるし、うまく行くはず・・・ホッうまく行きました。ただしこれだと、リフレッシュのたびに無駄な移動処理が走るので、初回のみこの処理がされる様に、シートのフラグを使用して制御することにした。ウィンドウ作成時に透明色指定があればフラグをセットして、初回呼び出しでリセット。う〜ん、いいカンジかも。

 

Step-2

うむ、きれいに表示できました。

 


Step-3

今回は星を表示してみた。彼方より迫り来る星を表現したつもりだ。なぜ時計にこんなものが必要かというと・・・趣味です。ぶっちゃけた話、いらない機能だ。どうでもいいところに力を入れてみるのも楽しいもんです。迫り来る、というところを表現する為に、ちょっと3Dチックな計算を入れている。点を描くAPIは本編で実装済なので、ちょいちょい、と・・・うんうん、そんなカンジに見える見える(自己評価)。

 

Step-3

星が迫ってきます。画像でわかるでしょうか?

 


Step-4

さて、そろそろ本来の趣旨である、時計機能の実装を始めるとしよう。ぐは、そもそもこのOSにはシステム時計機能が付いてないんだった・・・でも安心。サポートページから辿って行くと、読破した人向けのページがあって、その中にちゃんと時刻を取得する方法が記述されている。このページには、本編を読破してない人は混乱する可能性があるので、オススメでない旨の注釈があるが、rapperは読破しているので読んでもいいのだ。

 

ちなみに、こめんと欄にrapperが書いたコメントがあるのだが、なんでこんな細かいことに気づいたかというと、サンプルをコピペして実験したからに他ならない。えへへ。他の人はこんな横着はしないだろうけど、万一同じ様な人がいるとかわいそうなので、一応コメントしておいた。

 

そんなこんなで、無事時刻が取得できる様になったので、システム時計用のタスクを追加して、OSで時刻を保有することに成功した。お約束でタスクバーの右端に表示しておいた。くぼみにピタッと収まるので気分がいい。仕上げにアプリから時刻取得ができる様にAPIを作成して作業完了。これで安心して本来の時計作りに集中できる〜・・・たぶん。

 

Step-4

ようやく本来の目的が見えてきた〜。

 


Step-5

時刻が表示できる様になったら、次は針を描画しよう。線を描くAPIも本編で実装済だし、sin/cosで針の先端の座標を計算してホイホイ・・・一般保護違反出ました(汗。アプリのソース自体には問題なさそうなので、リンクしているライブラリ等を調べてみるが、ようわからんです。使えそうなのに・・・。いろいろいじっていると、どうやらそもそも小数の計算(double)でダメっぽいカンジ。これってrapperが悪いの?(しくしく。アセンブラソースを出力して、ちゃんと調べれば良いんだろうけど・・・。と、ここで、本編に「小数を自由に扱う準備ができていない・・・」という記述があったのを思い出した。線を描く処理を実装している部分だ。小数問題の解決は難しそうなカオリがするし、sin/cosなんて精度を要求しなければすぐに作れちゃうので、intを返すsin/cos関数を作ってみた。線の長さも一緒に渡して、計算した結果を整数で返す様にした。もはやこのアプリ専用関数っぽいけど、まあいいや。だってうまく表示できたも〜ん。

 

Step-5

ちょっと正攻法じゃない気がするけど、とりあえず満足。

 


Step-6

ところで、このアプリやたらチラつきませんか? って実際動かしてるのはrapperだけなんだけど、チラつくんですワ。その理由は描画関係のAPIをコールすると、APIの中でリフレッシュをするので、その範囲によってはチラチラするんだよね。自作で追加したAPIも同じ。知っていたさ。でも良い解消方法を今まで思いつかなかったのさ。既存のアプリに影響しちゃうのも嫌だしね。で、考えたのが、ウィンドウ毎に自動でリフレッシュするかどうかのフラグを保有して、そのフラグがONの場合は自動でリフレッシュしない、という動作に描画関係のAPIを直せばいいのだ。フラグはシートのflagを利用してと、自動リフレッシュの有効/無効を切り替える為のAPIを実装。初期設定を有効にしておけば、現行アプリに影響はない、と。これでどうだ〜・・・ぉぉ、チラつかない。スゲェ。動作画面では全くわからないのがつらいところ・・・。念の為、他のアプリをちょちょいと起動。うむ、影響はない様だ。ヨカッタ。

 

Step-6

うまくいきました。気持ちだけ感じ取ってください(笑。

 


余談その1

最初はウィンドウ移動の為に、マウス操作が自由にできる様にWindowsのウィンドウプロシージャみたいな仕組みを作ろうと考えていた。しか〜し、元ウィンドウのタイトルだった部分をドラッグすると移動できちゃうんです(透明色以外の部分ね)。ははは、こりゃいいや、ってことで、横着してそのまま仕組みを作ってない訳で・・・。終了もEnter押せばいいから問題ないし、とりあえずこのまま進んで、必要に迫られたら作るってことにしよっと。

 

余談その2

ウィンドウの自動リフレッシュ問題だが、実は、各描画関連のAPIを自動リフレッシュをしない様に呼び出すことができる。シートを指定する際に、シートへのポインタに+1して呼び出せば良い。このことをrapperは完全に忘れていて、わざわざ抑制機能を作ってしまったのだが、改めてソースコードを読み直しているときに気づいてしまった。はて、どうしたものか。まあ、いまさら機能を削るのもなんなので、しばらくは併用ってことで。少しは便利かも(汗。