WM_PAINTとBitBltについての質問

このQ&Aのポイント
  • 質問者はWindowsプログラミングを1月半ほど始めた初心者であり、WM_PAINTとBitBltに関する疑問があります。
  • 質問者は副スレッドを使用して図形を動かすプログラムを作成しましたが、画面がちらつく問題が発生しています。
  • 質問者はWM_PAINTの再描画による画面のちらつきの原因やBitBltの使用によるちらつきの回避方法について知りたいとしています。
回答を見る
  • ベストアンサー

WM_PAINTとBitBlt

レベルはWindowsプログラミングを始めて1月半、それ以前にプログラミング経験はありません。 環境は、VC++6.0 WindowsXP SP2です。 WINAPIしか使えません(MFCは分かりません)。 宜しくお願い致します。 定期的に図形を動かすプログラムを副スレッドを用いて作りました。 副スレッドにはSleep(5msスリープ)を入れてあり、スレッドの最後にInvalidateRectを実行し、WM_PAINTを発行して再描画させているのですが、動作は所望な通りなものの、画面がちらついてしまいます。 所持している参考書を読むと、図形を動かす処理を直接ディスプレイに出すのではなく、メモリDCに一度出力し、その後BitBltでディスプレイに出力すればよい(ダブルバッファのことらしい?)、と書いてありました。 また、あるサイトには、WM_PAINTが実行されるとOnEraseBkgndが走るからちらつくとも書いてあり、何だか良く分かりません。 (別のサイトにはOnPaintが走るとか、OnPaintBackgroundが走ると書いてあり、何が本当なのか???) 自分の知りたいことは以下の通りです。 1)WM_PAINTで画面の再描画を行うと画面が何故チラつくのですか? また、ちらつかない様にする方法はあるのでしょうか? 2)BitBltを用いるとチラつかないのは何故でしょうか? 3)参考までにですが、メモリDCでBitBltで転送、以外に画面をチラつかせずに画面を更新させる方法はあるでしょうか? 色々サイトを探してみてのですが、断片的にしか書いておらず、結局自分が所望する回答は得られませんでした。 初心者レベルなので、分かりやすく説明して頂けると大変嬉しいです。 以上、宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★アドバイス >1)WM_PAINTで画面の再描画を行うと画面が何故チラつくのですか?  ↑  チラツキの原因  (1)WM_ERASEBKGNDメッセージで背景を描画(塗りつぶし)  (2)WM_PAINTで前景(図形など)を描画(ここでちらつく)  チラツキの対策  (1)メモリDCを1つ用意  (2)用意したメモリDCに背景部分を描画  (3)用意したメモリDCに前景部分を描画←図形や文字など  (4)InvalidateRect()を実行  (5)WM_PAINT内で用意したメモリDCを画面のDCへBitBltでコピー(上書き)  (6)これでちらつかずに描画が可能 >2)BitBltを用いるとチラつかないのは何故でしょうか?  ↑  WM_ERASEBKGNDメッセージで背景が塗りつぶされるためちらつきます。瞬間だけ。  だからWM_ERASEBKGNDメッセージを処理して下さい。  処理といっても単純に『return 0;』を返すだけで良い。  つまりプロシージャで『case WM_ERASEBKGND:return 0;』とする。 3)参考までにですが、メモリDCでBitBltで転送、以外に画面をチラつかせずに画面を更新させる方法はあるでしょうか?  ↑  過去に私の回答を参考にして下さい。  http://oshiete1.goo.ne.jp/qa3052870.html→『画面がチカチカする』  回答No.3に『CASE WM_ERASEBKGND:return 0;』の1行を追加して試して見て下さい。  なお、メモリDCはWM_CREATEで作成してスレッドにそのメモリDCのハンドルを  引数として渡せば良いでしょう。またはグローバルな変数にしても動きます。

参考URL:
http://oshiete1.goo.ne.jp/qa3052870.html
supertrap
質問者

お礼

回答有難う御座います。 正直なところ、デバイスコンテキストの概念さえも良く分からない状態だったので大分時間がかかってしまいましたが、頂いたアドバイスとソースコードのお陰で、やっとちらつきを止めることが出来ました。 どうも有難う御座いました。

その他の回答 (1)

  • shred
  • ベストアンサー率35% (25/70)
回答No.1

Windowsはあまり使わないのでよく知りませんが ちらつきの原因としてはWM_PAINTがくると画面を塗りつぶした上で 描画が行われるのでチカチカするのだと思います。 BitBltではそれを回避することができるのだと思います。

supertrap
質問者

お礼

回答有難う御座います。 お陰様で解決いたしました。

関連するQ&A

  • クライアント領域を再描画させない方法

    クライアント領域で左クリックを押したままマウスを移動させた時の処理 (WM_MOUSMOVE)として、マウスの位置情報を、 InvalidateRect(hWnd, NULL, FALSE); でWM_PAINTに送り、WM_PAINTで描画処理をさせます。 右クリックでの処理として、 case WM_RBUTTONDOWN:    InvalidateRect(NULL, NULL, TRUE);    return 0; とした時、WM_PAINTでは 右クリックによるWM_PAINTでは、クライアント領域を 再描画させない様にしたいのですが、 どのようにしたら良いのでしょうか? クライアント領域に描画されたのを再描画させないことで、 消したいのです。 MS VC++ & Win98 の環境で作成しています。

  • Bitmapを重ね合わせる方法

    最近プログラミングを始めた初心者です。 環境はXP SP2 及びVC++6.0 です。 Win32APIのみを用いてプログラミングしております(MFCは使えません)。 宜しくお願い致します。 やりたいことは、あるビットマップを背景にして(bmpback.bmp)、その上に、bmpback.bmpよりサイズが小さいbmp1.bmpとbmp2.bmpを、WM_TIMERを使って交互に表示させる、です。 その際、WM_TIMER内でbmpback.bmpとbmp1.bmp(又はbmp2.bmp)を重ね合わせたbitmapを作成し、そのbitmapをWM_PAINT内でBitBltなどを用いてメモリDCからクライアント領域用のDCに転送して、ディスプレイに表示させたいと考えています。 検索したところ、以下のリンクに正に同じ質問があったのですが、難しくて理解出来ませんでした。 http://oshiete1.goo.ne.jp/qa1474735.html 回答者様が、良回答20ptで書かれている内容の、 >最終的に表示したい大きさのビットマップをメモリDCに割り当てて、 >そのメモリDCに対して10回のBitBltを行います。 の部分です。 最終的に表示したい大きさのビットマップ、というのが私の場合bmpback.bmpになると思いますが、例えばbmpback.bmpがSelectObject()でメモリDCに関連付けされているとして、そのメモリDCにbmp1.bmpをBitBltで転送する場合、bmp1.bmpに関連付けられるべきDC(デバイスコンテキスト)は何になるのでしょうか? (メモリDC→メモリDCかなあとも思ったのですが、それだとbmp1.bmpを紐付けした時点でbmpback.bmpが消えてしまうような気がして、ちょっと違うかなあと) 分かり辛い説明で申し訳ありませんが、知りたいことは、あるBitmapに別のBitmapをBitBltで転送して重ね合わせたい場合、コピー元のビットマップに関連付けるDCは何にすべきか、ということです。 本当は透過処理もしたいところですが、それは後で調べることにしてまずはBitBltで動作を見たいと思っています。 宜しくお願い致します。

  • [Active Basic]BitBltで画像を表示

    ActiveBasicでプログラムを書いています。 少しずつデバイスコンテキストが使えるようになってきて、簡単なブロック崩しを作ってみようと思い、作り始めました。 以前、デバイスコンテキストを使えるようになろうと、上から物体が降ってきて、それを避けるというゲームを書いてみたのですが、画像(ビットマップ)の表示方法が分からず、すべて MainWnd_Paint(hDC As HDC) に中に書きました。 すると、処理ごとにいらないものまで描写されるので画面がかなりちらついてしまいました。 ActiveBasicのヘルプ(http://www.activebasic.com/help_center/articles/win32/step16/index.html)を参考にして、プログラムを書いてみたのですが、背景が描写されません。 コードを下に書きますので、すみませんが添削の方をお願いします。 まだ、プログラムを始めたばかりのほやほやですので、なるべくやさしくお願いします。 '------------グローバル------------ Dim ImgBack As HBITMAP '背景画像 Dim hBackDC As HDC '背景画像用デバイスコンテキスト Dim hMemDC As HDC 'BitBlt用のデバイスコンテキスト '------------グローバル------------ Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT) Dim hDC As HDC 'イメージを読み込んでいく ImgBack = LoadImage(0,".\pic\back.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE) 'デバイスコンテキストをそれぞれ作成 hDC = GetDC(hMainWnd) hBackDC = CreateCompatibleDC(hDC)'背景用DC hMemDC = CreateCompatibleDC(hDC)'BitBlt用DC '背景を描写 SelectObject(hBackDC,ImgBack) BitBlt(hMemDC,0,0,640,480,hBackDC,0,0,SRCCOPY) '最後にhDCだけ開放 ReleaseDC(hMainWnd,hDC) End Sub Sub MainWnd_Paint(hDC As HDC) End Sub 後、BitBltを MainWnd_Paint(hDC As HDC) の中に表記すると、画像が表示されます。 何故か、いまいち分かっていません・・・ すみませんが、ご教授ください。

  • ダブルバッファの作り方

    画面に描画するBCC5.5 のCプログラムがあります。画面がちらつくので、ダブルバッファにしたいのですが、具体的に、どの関数を呼んで実装したらよいのかわかりません。WEB検索をしますと結構情報がヒットしますが、解決に至ってませんので、よろしくお願いします。 具体的にやったことは、現在動いているプログラムの case WM_PAINT:  hdc=BeginPaint(hWnd,&ps);  paint(hdc); // 自作の描画プログラム本体  ReleaseDC(hWnd,hdc);  EndPaint(hWnd,&ps);  break; の部分を、「画面サイズのビットマップイメージhBitmapをつくり、そこにpaint関数で描き込み、最終画面を一気に出力する」というつもりで以下のプログラムに書き換えたのですが、表示すらしなくなってしまいました。何が悪いのかお教えください。 case WM_PAINT:  GetClientRect(hWnd,&rt);   h = (int)rt.bottom;   w = (int)rt.right;  hBuffer = CreateCompatibleDC(NULL);  hBitmap = CreateCompatibleBitmap(hBuffer, w, h);  SelectObject(hBuffer, hBitmap);  paint(hBuffer);  hdc=BeginPaint(hWnd,&ps);   BitBlt(hdc, 0,0,w,h, hBuffer,0,0, SRCCOPY);  ReleaseDC(hWnd,hdc);  EndPaint(hWnd,&ps);  DeleteDC(hBuffer);  DeleteObject(hBitmap);  break;

  • WINAPI 他のウインドウを重ねると画像やテキストが消える

    C++とWINAPIで、ウインドウを作成し、テキストや画像を表示しています。 このウインドウに他のウインドウを重ねて、再度、このウインドウを表示すると画像やテキストが消えてしまいます。 case WM_PAINT: BitBlt( hbtn0DC, 0, 0, 40, 40, hbtn0bmpDC, 0, 0, SRCCOPY ); return 0; 再描画するタイミングで表示するようにしています。 他のウインドウが被っても消えないようにする方法を教えてください。 もしくは、 他のウインドウが被っても画像が消えないようにする処理を説明しているページをどこかで見たような気がするのですが、見つかりません。 ご存知でしたら教えてください。

  • クライアント領域の保存

     初歩的な質問でごめんなさい。 VC.netのMFCで、OnLButtonDownで描画の処理をしているのですが、これだと画面を最小化したりするとクライアント領域に描画していたものが消去されてしまうので、画面全体のビットマップをメモリに保存しておきOnPaint関数でブロック転送すればよいと参考書に載っているのですが、このメモリに保存してブロック転送というのがうまくできません。  BitBltを使うのはわかるのですが、どうもうまくいきません。よろしければ、恐縮ですがソースを教えていただきたいです。お願いします。

  • 画面の再描画について

    VCのMDI(CFormView)での画面の拡大・縮小などをした時の再描画の仕方がわかりません。OnInitialUpdateに何かを記述するか、WM_PAINTを追加したりすればいいのですか?初心者なのでよろしくお願いします。

  • Windows API ペンを作るタイミング

    ゲームのプログラミングをしています。 テキストのサンプルプログラムではペンやブラシをWM_CREATEの中で hPen[1] = CreatePen(PS_SOLID, 2, RGB(50,70,0));    :    : のような感じで生成して WM_PAINT内でSelectObject(hdc, hPen[i]); として使っているのですが 自分のプログラムはPaintという関数を使っています。 その場合Paint(~)にそれらの配列を渡す形で良いのでしょうか? 一応今はそれで動いてます。 ただ描画の処理は1つの関数にまとめると書いてあったので Paint内で生成&削除をした方がよいのかとも思いまして・・・ どっちが一般的なのか、どういう場合はどうすればいいのかっていうのが 経験がなくて全然わからないので教えて欲しいです。 一応落ち物ゲームやシューティングゲームを想定してます。

  • WindowsAPIでの画像表示について

    コード(一部): http://fatalita.sakura.ne.jp/goo/img/APIcode.jpg 本当はこうしたかった実行結果: http://fatalita.sakura.ne.jp/goo/img/Run2.jpg 実際の実行結果: http://fatalita.sakura.ne.jp/goo/img/Run.jpg 現在Windowsプログラミングでウィンドウプロシージャの WM_CREATE 内で仮想画面にtest.bmpを読み込み、 さらにその後に仮想画面に大きな赤い四角形を描画させて WM_PAINT で裏画面をウィンドウに描画させているのですが、 何故かこのコードを実行すると画像ファイル test.bmpの大きさの範囲内でしか赤い四角形が描画されません。 これは何が悪いのでしょうか・・? 開発環境はWinXP / VisualStudio 2005です。 後、WND_SIZE_XとWND_SIZE_Yはそれぞれウィンドウのサイズを表しています。

  • タブをオーナードローすると、ちらついてしまいます

    質問させていただきます。 WindowsSDKを用いて、画面を作成しています。 MFCは使用していません。 タブを使っていますが、タブは作成時にTCS_OWNERDRAWFIXEDを指定しています。 WM_DRAWITEMメッセージが来たら、タブを描画していますが どうしてもちらつきが目立ってしまいます。 WM_DRAWITEMでの処理は、初めにタブの裏画面に描画し 最後にタブに通知された、DRAWITEMSTRUCTのhDCに裏画面の内容をBitBltで転送しています。 メイン画面もダブルバッファリングを行っておりますが、メイン画面はちらついていません。 タブ側で、WM_ERASEBKGNDで何もせずreturnすると、ちらつきはなくなりますが 背景色で塗りつぶされなくなるため、タブが表示される箇所にウィンドウを上に置いたりすると そこが残ってしまいます。 WM_DRAWITEMが頻繁によばれているため、これはちらついているのでしょうか? 解消方法に頭を悩ませております。 どうぞご教授の程お願いいたします。

専門家に質問してみよう