時乃工房-Windowsとアマグラマーな関係-

アクセスアップにオートリンクネット リンクが自動で増殖オートリンクの登録はこちら 節約内職情報検索局
ページランク向上リンク集
役立つリンク集 Web Links
SEO対策ディレクトリ型検索エンジン Su-Jine
メニュー
トップ
アマグラミング
C++編 目次
第11章
第13章
ソフトウェア開発製品
相互リンク

<勘違いだらけのアマグラミングな日々(C++編)>

第12章 豆腐を並べる(2)

2006年10月4日

前章では、マウスによる入力と、クライアント領域内の任意の場所への描画を試みてみた。
結果、マウスからの入力を処理することには成功したわけだが、描画部分に問題を抱えていることを匂わせての放置となった。

では、具体的にどのようなバグを抱えていたのか。
実は、"List002-004a""List002-005"では表示された内容を保持出来ないのである。
具体的には、ビルドした実行ファイルを実行して以下のようなテストを行ってみれば、一目瞭然である。

<白い四角の描画>まず、"List002-005"を実行した状態で、白四角をポチポチと並べてみよう。

適当にちりばめたところで、今度は他のウィンドウで上をなぞってみる。
すると、なぞったところの描画部分が黒くなって、元に戻ってしまう。
状況は左の図のとおり。

"List002-004a"にいたっては、もう目も当てられないくらい致命的だ。
こちらは、白四角をたくさん並べた状態からウィンドウを動かすだけで、最後に描画した白四角を除き、全てが無に帰する。
これでは何の役にも立たない。

なぜこのような現象に陥ってしまうのか?
とりあえず"List002-004a""List002-005"の動きの違いから、関数BeginPaint()は再描画の必要な個所だけに働き、関数GetDC()は全てを描きなおすように思える。
これはこれで、ちょっとした成果だ。
使い分けの参考程度にはなる。

しかして、これらの問題をクリアする前に、ソースと頭を整理しておこう。

List.002-006
main_window.h
main_window.cpp
main_callback.h
main_callback.cpp
graphics_control.h
graphics_control.cpp
bitmap.rc
main_menu.h
main_menu.cpp
main_menu.rc
<ソースのダウンロード>

このソースは"List002-005"をもとに、白四角の描画部分を関数SetCharacter()としてまとめ出したものである。
私の場合、今回のような、おそらく大きな変更を強いられるであろう状況に出会ったときが、機能の細分化を行う良い機会だと考えている。
また、頭の悪い私にとって、この作業は変更するべきソースの見通しを良くしてくれる意味合いも持つ。
とりあえず、"List002-006"は機能的には"List002-005"と変わらず、よってバグの修正も行われていない

さて、ではどようにしてこの現象を修正しようか?
まず考えたのは、デバイスコンテキストの開放によって内容が失われたのではないか、と云う仮説。
もしこの仮説が正しいのであれば、描画する度に開放していたハンドルを、アプリケーションの実行中保持しつづければよいことになる。
そこでこの仮説に基づき、以下のようなソースを用意してみた。

List.002-007
main_window.h
main_window.cpp
main_callback.h
main_callback.cpp
graphics_control.h
graphics_control.cpp
bitmap.rc
main_menu.h
main_menu.cpp
main_menu.rc
<ソースのダウンロード>

このソースでは、まずデバイスコンテキストのハンドル仮想デバイスコンテキストのハンドルをそれぞれグローバルな変数とし、関数SetupGraphics()内で各ハンドルを取得するようコーディング。
そして、WM_CREATEメッセージでこれを呼出している。
最後に使い終わったハンドルは、関数ClosedownGraphics()を作ってやり、WM_CLOSEメッセージで処理して完成。

で、出来上がったソースをビルドしてやり早速実行してテスト、とこんな流れである。
しかして、その肝心なテストの結果は?・・・
あえなく玉砕、まったく解決にはなっていなかった

ここまできたら後には引けない(?)。
どうしようもない仮説は捨て去り、力技で解決することにした。
それはバッファリング
簡単に云ってしまえば、クライアント領域と同じ容量のメモリを他に確保して、通常の描画はそこに行い、あるタイミングでその内容をクライアント領域へコピーしてやる方法である。
あるタイミングとは今回の場合、WM_PAINTメッセージが呼出される時、としよう。

List.002-008
main_window.h
main_window.cpp
main_callback.h
main_callback.cpp
graphics_control.h
graphics_control.cpp
bitmap.rc
main_menu.h
main_menu.cpp
main_menu.rc
<ソースのダウンロード>

今回無い知恵絞って考えたバッファリングの方法は、クライアント領域と同じサイズのBitMapデータを用意して、WM_PAINTメッセージを受取るたびにこのBitMapデータを描画してやろう、と云うものだ。
正直、メモリの使用量と速度の面で不安が残るが、他に良い方法が思いつかなかったのだからしょうがない。
まずは、関数SetupGraphics()再製作。
ここで最初に行うことは、クライアントエリアと互換のあるデバイスコンテキストを作成
次にクライアントエリアと互換性のあるBitMapデータ(!)を作り、先に作った互換デバイスコンテキストと関連付けを行い、このBitMapデータを黒く塗りつぶしている
そして、関数SetCharacter()における描画対象を、この互換デバイスコンテキストに変更してやる。
あとはこの互換デバイスコンテキストの内容をクライアント領域にコピーする為に、関数BildClientArea()を用意してやり、WM_PAINTメッセージの処理として呼出してやれば良いはずだ。
おっと、事後処理として関数ClosedownGraphics()の用意もお忘れなく。

こうして出来上がったアプリケーションをテストしてみると、なるほど、うまく作動しているようだ。
折角並べた白四角も、もう一安心、削除されること無くアプリケーションが終了するその時まで、クライアント領域に存在している。
懸念事項だったメモリ容量と速度の問題も、まぁ、気にするほどでも無かったようだ。
と云うか、昔、数キロバイトしかアクセス出来なかったメモリ空間も、ここ二十数年の間に状況が全く変わってしまった。
このアプリケーションも、Debugでビルドしたものとは云え、3メガバイトものメモリ容量を必要とするが、メインメモリが数百メガバイト数ギガバイトともなる現代のPC上では、気にする程の事ではなくなってきている。
なんか感慨深いと云おうか、拍子抜けすると云おうか・・・

さて、ここまできたら画面処理は出来上がったも同然。(ホンマか?)
意気揚揚と次のステップを目指すことにしよう。

・・・ところでどんなゲームを作るんだっけ?

<前章> <目次>





<時乃工房>
Net Office Nakai
メビウスリング投稿掲示板には小説日記ゲームアニメコミック小学生中学生などの掲示板過去ログがあります。相互リンクも募集中。