• ベストアンサー
  • 困ってます

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で転送、以外に画面をチラつかせずに画面を更新させる方法はあるでしょうか? 色々サイトを探してみてのですが、断片的にしか書いておらず、結局自分が所望する回答は得られませんでした。 初心者レベルなので、分かりやすく説明して頂けると大変嬉しいです。 以上、宜しくお願い致します。

共感・応援の気持ちを伝えよう!

  • 回答数2
  • 閲覧数1786
  • ありがとう数2

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

  • ベストアンサー
  • 回答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

共感・感謝の気持ちを伝えよう!

質問者からのお礼

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

関連する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で動作を見たいと思っています。 宜しくお願い致します。

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

    画面に描画する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;

その他の回答 (1)

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

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

共感・感謝の気持ちを伝えよう!

質問者からのお礼

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

関連するQ&A

  • 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はそれぞれウィンドウのサイズを表しています。

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

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

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

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

  • BitBlt関数について教えてください

    よろしくお願いします。 画像を読み込むための、BitBlt関数について、色々調べてみたのですが、どうしても分からない記述が2つあります。ご指導、アドバイスをお願いします。 1、サンプルのソースを参考にしているのですが、BitBlt関数の第2、第3の記述の意味として、 『PAINTSTRUCT構造体のポインタpsが、左隅上、を参照している』と解釈したのですが、第4、第5引数の、-(引く)の意味が理解できません。 2、画像を2種類表示するためメニューに、『オプション1とオプション2』を作り、オプション1はコピー元と同じ画像を表示、 オプション2は、ラスタオペレーションを選択可能にして、選択した画像を表示すると言うものですが、DWORD dwRop; を宣言し『第9引数をNOTSRCCOPY』として、二つ目の画像を表示する case文に dwRop = NOTSRCCOPY; を追加したのですがうまく行きません。多分 『dwRop』の使い方に問題があるのかと思うのですが、うまく表示されません。 因みに、 BitBlt関数の第9引数が『SRCCOPY』の時は、正常に2種類の画像が表示されます。 /*ウィンドウプロシージャ*/  LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)  { HDC hdc;  DWORD dwRop; //追加した  PAINTSTRUCT ps;  HBITMAP hBmp;  HDC hdc_memx;  switch(msg){  case WM_CREATE:  hdc = GetDC(hWnd);  hBmp = LoadBitmap(hInst, "MYBMP1");  if(hBmp == NULL){  MessageBox(hWnd, "画像1のロードに失敗しました", "エラー",  MB_OK | MB_ICONWARNING);  return 0;  }  hdc_mem1 = CreateCompatibleDC(hdc);  SelectObject(hdc_mem1, hBmp);  DeleteObject(hBmp);  hBmp = LoadBitmap(hInst, "MYBMP2");  if(hBmp == NULL){   MessageBox(hWnd, "画像2のロードに失敗しました", "エラー",   MB_OK | MB_ICONWARNING);  return 0;  } hdc_mem2 = CreateCompatibleDC(hdc);  SelectObject(hdc_mem2, hBmp);  DeleteObject(hBmp);  ReleaseDC(hWnd, hdc);  break;  case WM_PAINT:  BeginPaint(hWnd, &ps);  if(show_no == 1) hdc_memx = hdc_mem1;  if(show_no == 2) hdc_memx = hdc_mem2;  BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdc_memx, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);  // PATCOPYにして,IDM_ANIME2に、dwRop=NOTSRCCOPY //を追加しても変更されないし、画像の表示が出来ない EndPaint(hWnd, &ps);  break; case WM_COMMAND: switch (LOWORD(wp)){ case IDM_ANIME1: show_no = 1;      //dwRop = SRCCOPY //追加したが変化なし InvalidateRect(hWnd, NULL, TRUE); break;  case IDM_ANIME2: show_no = 2; //dwRop = NOTSRCCOPY; //追加したが変化なし InvalidateRect(hWnd, NULL, TRUE); break;  case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; } break;  case WM_DESTROY: DeleteDC(hdc_mem1); DeleteDC(hdc_mem2); PostQuitMessage(0); break;  default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

  • 画面の再描画について

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

  • [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) の中に表記すると、画像が表示されます。 何故か、いまいち分かっていません・・・ すみませんが、ご教授ください。

  • CreateCompatibleDCを初期化時にしたい(MFC)

    MFCでJPEG画像を表示するプログラムを OnPaint() の中に書いていたのですが・・・  : bool m_bImageMemDCInit; CImage m_Image; CBitmap *m_pImageBitmap; CDC m_ImageMemDC;  :  : void CChildView::OnPaint() {  CPaintDC dc(this);  if(!m_bImageMemDCInit){   m_bImageMemDCInit = true;   // イメージをロード   m_Image.Load("test.jpg");   m_pImageBitmap = CBitmap::FromHandle(m_Image);   m_ImageMemDC.CreateCompatibleDC(&dc);   m_ImageMemDC.SelectObject(m_pImageBitmap);  }  // 描画  dc.BitBlt(0, 0, 256, 256, &m_ImageMemDC, 0, 0, SRCCOPY); } このように、Load や CreateCompatibleDC などの初期化にあたる処理を、起動時に1度しか処理しないように書いています。 しかし、このプログラムではあまりに汚い。どうにかして PreCreateWindow などの初期化関数内に書きたいのですが、CreateCompatibleDC 関数で CPaintDC* を渡す必要があるので、OnPaint 関数内に書かざるを得ないのです。 (Loadだけなら初期化関数内に移せるのですが・・・) いっそ CreateCompatibleDC を再描画のたびに呼んでもいいのでは? と思い、やってみると異常終了してしまいました。 また、CPaintDC dc(this); を PreCreateWindow 関数内に書いても異常終了しました。 どなたかスマートな方法をご存知でしたら、ご指導願います m(_ _)m

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

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

  • 文字のちらつきを抑えるには

    VisualStudio2005でAPIをを使ってマウスの位置を表示するソフトを作っています。WM_MOUSEMOVEメッセージがきたら位置を取得して、InvalidateRect関数を使って再描画しています。再描画する際に文字のちらつきが気になります。HPを調べたりいろいろやってみたのですが、ちらつきを起こす原因と対処法(ダブルバッファリング)の大まかな部分しか分かりませんでした。もし、参考になるサイトや詳しい方がいらっしゃったらご教授ください。※MFCは使っていません。

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

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