[[BORLAND C++]]
INDEX
Section.17 Beginner Graphics
とりあえずだが、グラフィックに挑戦なのだ。Windowを一枚開いて、そのまま描画させても良かったのだが、前項からの続きで、別のWindowを開いて描画する方法に挑戦したら、いろいろな問題が…

  • いきなり、デスクトップに落書きしてしまった(汗);
    前回のプログラムを元に、メインウインドウと、グラフィックウインドウの2枚を開いて、メインウインドウのWM_PAINTイベントで、グラフィックウインドウのクライアントに直線を描画する様にプログラムしたら、いきなりデスクトップのマイコンピュータ辺りに直線が描画されてしまった…。狙ったWindowにも直線の描画はされたのだが…。これが何故、こうなるのかを考えて、またハマってしまったのだ。つまり、メインのWindowは、ここまでに、少なくとも2回のWM_PAINTを受けている事になる。1回目のWM_PAINTは、多分、CreateWindowにて、親Windowを開いた後,UpdateWindow()を実施している時で、2回目は、子Windowが生成されて、描画された時だと思う。問題は、この1回目なのだ。この時点で、グラフィックウインドウは生成されていないので、ウインドウハンドルも、未確定のままだったのである。この状態で、グラフィックウインドウに描画するという行為は、即ち、デスクトップへの描画になってしまう訳だ。

  • さて、次の問題が…
    上述した問題の原因が分かったので、とりあえず、次に進もう…と、サンプルを造ってみた。う〜ん,思ったより簡単にできたぞ!,次は色を変えて…と、思っていたら、さっきまで表示されていた描画が真っ白になっていたのである。あれれ??
    再度、描画を行ったら同じように書けたのだが、また、暫く調べものをしていたら消えてしまっていた…。まさか?と思って、再度描画し、Windowをバックグラウンドに隠してから、フォアグラウンドに戻してみると…あ!真っ白!?
    サンプル018←試してみる?
    そうなのである。ウインドウがバックグラウンドから、フォアグラウンドに現れる時、ウインドウには、WM_PAINTのイベントが挙がるのだ。このサンプルでは、WM_PAINTのイベントでは、BeginPaint()EndPaint()しか行っていないので、WM_PAINTのイベントで、画面は真っ白になってしまうのだ。もし、このBeginPaint()EndPaint()の間に、グラフィックの表示プログラムを書いていれば、毎回描画を行ってくれるし、ボタンの様なウインドウ・オブジェクトならば、そちらにもWM_PAINTのイベントが上がるので、再描画されるのだが、オブジェクトでも無い単なる図形として描かれたグラフィックは、残念ながら、再描画されないのである。 このサンプルでは、メニューの描画か、グラフィックウインドウでのマウスの左ボタン押下で描画を行っていたので、描画の後でWM_PAINTが上がると、全部消えてしまうという訳である。

  • メモリDCを仮想画面として使う
    では、WM_PAINTのイベント中に、描画コマンドを記述すれば良いのだろうか?確かに、毎回決まった描画を行う様な場合には、これで問題無いのだ。でも、それでは、グラフィックエディタの様に、ユーザの操作で表示内容が変化する様な場合には困るのである。全部手順を記憶しておいて、再度実施するという方法もあるが、それではあまりにも非現実的だ。では、どうするのだろう??
    何か、グラフィック画面を操作した時、その画面を保存して…再描画の時に貼り付ければ…とか、グラフィック画面を表示させている場合は、フォアグラウンドをキープするとか色々考えたが、多分、一番良い方法は、メモリDCにて仮想画面を作成し、そこへの描画を行って、画面にコピーする方法だろう。この方法ならば、WM_PAINTの処理でも、仮想画面からのコピーだけで済むのである。手順は以下の通りである。

      まずは準備から、
    • 描画を行おうとしている画面のデバイスコンテキスト(DC)を取得する。
      DC=GetDC(Whandle) ;

    • メモリデバイスコンテキスト(MDC)に、DCと互換性のあるDCを取得する。
      MDC=CreateCompatibleDC(DC) ;

    • HBITMAPにて、ビットマップの構造体(BM)を宣言し、DCと互換性のあるビットマップを生成する。
      BM=CreateCompatibleBitmap(DC,SizeX,SizeY) ;

    • 仮想画面をビットマップ(BM)に割り当てる。
      SelectObject(MDC,BM) ;

    • 念のため、ビットマップ画面をクリアしておく。
      PatBlt(MDC,0,0,SizeX,SizeY,WHITENESS) ;

      以上で準備はOK、では描画を,
    • MDCに対して描画を行う。
      MoveToEx(MDC,10,10,NULL) ; LineTo(MDC,80,80) ;

    • 仮想画面を、実画面にコピーする。
      BitBlt(DC,0,0,SizeX,SizeY,MDC,0,0,SRCCOPY) ;
      ※WM_PAINTの処理では、これだけを行えば良いのだが、DCは、BeginPaintにて取得した、ps.hdcを使用すれば良い。

      後始末,
    • DCの後始末(使ったら毎回行う事)
      ReleaseDC(Whandle,DC) ;
      ※メモリDCについては、アプリの終了時で問題無い。

    • MDCとBMの後始末(アプリが終了するまでに行う)
      DeleteDC(MDC) ;
      DeleteObject(BM) ;


    サンプル019のソース
2002/05/08
HomeSweetHome2
Ozzy's Software