画面に描画する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;
No.3ベストアンサー
- 回答日時:
CreateCompatibleBitmapでメモリデバイスコンテキストを指定した場合、モノクロビットマップが作成されてしまいます。
この場合、CreateCompatibleBitmapにはスクリーンのデバイスコンテキスト(つまりBeginPaintで得られるDC)を渡す必要があると思います。
HDC hdcScreen = BeginPaint(hWnd, &ps);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmpMem = CreateCompatibleBitmap(hdcScreen, 幅, 高さ);
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
paint(hdcMem);
BitBlt(hdcScreen, rt.left, rt.top, 幅, 高さ, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmpOld);
DeleteObject(hbmpMem);
DeleteObject(hdcMem);
EndPaint(GetSafeHwnd(), &ps);
以下は参考意見なんですが(横やりを入れて申し訳ないのですが)、ちらつき防止のためだけなら、オフスクリーンバッファをあらかじめその都度作成&破棄するという方針でも良いと思いますよー
あかかじめ作っておく場合の利点は、高速化が期待できるところかと。
(その分リソースを確保しっ放しになるので、場合によって使い分ければ良いと思います)
回答ありがとうございます。
お教えいただいたソースを、No2さんの回答を参考に加工して以下の変更を加えたところ、スムーズな描画になりました。
ありがとうございました。
case WM_CREATE: に、
GetClientRect(hWnd,&rt);
WindowsHeight = (int)rt.bottom;
WindowsWidth = (int)rt.right;
hDC = GetDC(hWnd);
hMemBMP = CreateCompatibleBitmap( hDC, WindowsWidth, WindowsHeight );
hMemDC = CreateCompatibleDC( hDC );
SelectObject(hMemDC, hMemBMP);
ReleaseDC(hWnd, hDC);
を追加し、
case WM_PAINT:
GetClientRect(hWnd,&rt);
h= (int)rt.bottom;
w= (int)rt.right;
if(h!=WindowsHeight || w!=WindowsWidth) {
DeleteObject(hMemBMP);
DeleteObject(hMemDC);
再度、オフスクリーンバッファを作成
}
で、ウインドサイズ変更の場合の処理をして、
SelectObject( hMemDC, GetStockObject(NULL_PEN) );
SelectObject( hMemDC, CreateSolidBrush(RGB(0xFF,0xFF,0xFF)) );
Rectangle( hMemDC, 0, 0, WindowsWidth, WindowsHeight );
DeleteObject( SelectObject(hMemDC,GetStockObject(WHITE_BRUSH)) );
ReleaseDC(hWnd, hDC);
で、白で初期化して
paint (hMemDC);
で描画して、
hDC=BeginPaint(hWnd,&ps);
BitBlt(hDC, 0,0,w,h, hMemDC,0,0, SRCCOPY);
EndPaint(hWnd,&ps);
で画面に描く
No.7
- 回答日時:
★回答者No.2です。
>途中でウインドウサイズを変更することがあるので…
↑
ウインドウ・サイズが変更されたときの対策
・すでに回答者No.5(MrBan)さんが『WM_SIZE等のタイミングで作り直す。』と
回答している通りです。
でも次の3タイプがあります。
(1)毎回メモリDCを作成/破棄
(2)起動時にデスクトップ画面と同じ大きさのメモリDCを作成
(3)WM_SIZEやWM_DISPLAYCHANGEメッセージでメモリDCを作り直す
・(1)のメリットはメモリ量(リソース量)を描画時しか消費しない
(1)のデメリットは毎回メモリDCを作成/破棄するので低速
・(2)のメリットは毎回メモリDCを作成/破棄しないので高速
(2)のデメリットはメモリ量(リソース量)に無駄が出る場合あり
・(3)のメリットはメモリ量を必要最低限に作成/破棄も最低回数に抑えられる
(3)のデメリットはウインドウ・サイズや画面サイズの変更に手を加える手間がかかる
上記の3つより状況により選択して下さい。
再度、回答ありがとうございます。
No3さんのお礼に書いた私の対策はOh-Orangeさんの分類(3)に相当するわけですね。
わかりやすい説明と分類、ありがとうございました。
No.5
- 回答日時:
ANo1です。
CreateCompatibleDCの直後は、
DC自体はデバイス互換でもSelectされているビットマップは前述のものになります。
なので、「CreateCompatibleDCのビットマップ」 *ではなく*、
「画面と互換のあるビットマップ」に対してCreateCompatibleBitmapが必要です。
例えばBeginPatintのDCに対してCreateCompatibleBitmapする等。
> 問題がある場合、どのように対処すればよいのでしょうか?
WM_SIZE等のタイミングで作り直す。
> また特にエラーもなかったので
提示コードではやっていませんが、APIの戻り値は確認していますか?
再度、回答ありがとうございます。
>WM_SIZE等のタイミングで作り直す。
ご教示のとおりにプログラムしたら、スムーズな描画になりました。
具体的なプログラムは、No3さんのお礼に書いたとおりです。
>提示コードではやっていませんが、APIの戻り値は確認していますか?
確認してません。やはり確認したほうがいいのですね。アドバイスありがとうございます。
一緒のお礼になってしまいますが、MrBanさん、Oh-Orangeさん、mixmarionさん、適切なアドバイス、本当にありがとうございました。
No.4
- 回答日時:
No.3です。
サンプルコードの最後、
誤:EndPaint(GetSafeHwnd(), &ps);
正:EndPaint(hWnd, &ps);
でした。
ごめんなさい。
No.2
- 回答日時:
★アドバイス
>WEB検索をしますと結構情報がヒットしますが、
>解決に至ってませんので、よろしくお願いします。
↑
ここのQ&AのC/C++カテゴリでも検索しましたか?
つい昨日似たよな質問があり回答しました。
http://oshiete1.goo.ne.jp/qa4093552.html→『WM_PAINTとBitBlt』
または
http://oshiete1.goo.ne.jp/qa3052870.html→『画面がチカチカする』
が参考になると思います。
・あとWM_PAINTメッセージ内でなぜ
>ReleaseDC(hWnd,hdc);
を行っているのでしょうか?
>EndPaint(hWnd,&ps);
これをしているので必要ないと思います。
・WM_PAINTメッセージ内でデバイスコンテキストは
(1)BeginPaint()関数で取得
(2)EndPaint()関数で解放
これが基本。
だからWM_PAINTメッセージ内でGetDC()、ReleaseDC()関数を混ぜると
おかしくなりませんか?混乱しますよ。
・とにかく上記の2つの過去質問が参考になると思います。
参考URL:http://oshiete1.goo.ne.jp/qa3052870.html
回答ありがとうございます。
> つい昨日似たよな質問があり回答しました。
> http://oshiete1.goo.ne.jp/qa4093552.html→『WM_PAINTとBitBlt』
> または
> http://oshiete1.goo.ne.jp/qa3052870.html→『画面がチカチカする』
> が参考になると思います。
確かに、読んで見ると関係ありますね。「ダブルバッファ C言語」や「ダブルバッファ BCC」などで検索したので、上位に見つからなかったようです。
http://oshiete1.goo.ne.jp/qa3052870.htmlのNo3の回答、参考にしています。ありがとうございます。
早速ですが、No1さんのお礼にも描いたのですが、ひとつ質問があります。
CASE WM_CREATE: で hMemBMPとhMemDCを1回作って、それをStatic 変数として、毎回使用していますが、途中でウインドサイズが変更したとき問題ないのでしょうか? 問題がある場合、どのように対処すればよいのでしょうか?
>・あとWM_PAINTメッセージ内でなぜ
>>ReleaseDC(hWnd,hdc);
> を行っているのでしょうか?
>>EndPaint(hWnd,&ps);
> これをしているので必要ないと思います。
そうなんですか。EndPaint(hWnd,&ps);だけでは、hdc を開放するところがないのReleaseDC(hWnd,hdc);が必要かと思い入れてました。また特にエラーもなかったので、知らずにいました。ありがとうございます。
No.1
- 回答日時:
> hBitmap = CreateCompatibleBitmap(hBuffer, w, h);
とりあえず、CreateCompatibleBitmapの引数hBufferで意図しないbitmapを作りだしていませんか。
<MSDN引用:CreateCompatibleDC>
メモリデバイスコンテキストを作成した時点では、
その表示サーフェスはモノクロームであり、
高さと幅は 1 ピクセル×1 ピクセルです。
</MSDN引用>
何もでないように見えるのはこのあたりが原因では。
# バックバッファはあらかじめ作っておくべきでは。
回答ありがとうございます。
>とりあえず、CreateCompatibleBitmapの引数hBufferで意図しないbitmapを作りだしていませんか。
直前の hBuffer = CreateCompatibleDC(NULL); で、NULL を指定しているので、現在の画面と互換性のある、つまりフルカラーのメモリデバイスコンテキストが作成されていると思うのですが。
でも真っ黒な画面なので、モノクロームのようですね。どのように指定したらよいのでしょう?
<MSDN引用:CreateCompatibleDC>
既存のデバイスコンテキストのハンドルを指定します。NULL を指定すると、アプリケーションの現在の画面と互換性のあるメモリデバイスコンテキストが作成されます。
</MSDN引用>
># バックバッファはあらかじめ作っておくべきでは。
これなんですが、途中でウインドウサイズを変更することがあるので、初めに作っておくと、困るのではないのかと思って、毎回作ることにしたのです。はじめに作っておいて、ウインドサイズが変更されても、困ることは無いのですか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) Vba LongPtrについて教えてください 2 2022/08/19 11:14
- Access(アクセス) Vba Userformを前面に出すについて 3 2022/04/15 12:29
- Illustrator(イラストレーター) medibang paintで絵を描いて、A3やB3でコピーしたら線の画質が粗くなったのですが、解決 2 2023/04/04 06:48
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- 画像編集・動画編集・音楽編集 medibang paint を使っているのですが、 [画像をレイヤーとして開く]で写真をトレースし 2 2023/03/18 04:36
- その他(IT・Webサービス) JPG画像の入っているホルダーの写真を一括してネガからポジに変換したいのですが 2 2023/02/18 16:47
- Illustrator(イラストレーター) ペイントの印刷が出来なくなりました。 2 2023/08/08 10:00
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- マウス・キーボード HEIYO Surfaceぺんの使用方法を教えてください 2 2023/04/09 10:40
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
コントロール内の文字の背景色
-
デスクトップ撮影を実現するwin...
-
色描画
-
ビットマップ(表示速度とサイズ)
-
クライアント領域をCBitmapに取...
-
パレット番号で塗りつぶし
-
グラフの交点の求め方(Excel)
-
ゲームでは結局どっちが良いの?
-
マインクラフト(pc版)で座標...
-
エクセルで作った新しいウイン...
-
UWSCで特定のChromeのタブをア...
-
勝手にウィンドウが開いて止ま...
-
Tera Termに他のアプリから文字...
-
エクセルのコントロールツール...
-
コンボボックス内の文字サイズ変更
-
Labelの文字をスクロールする際...
-
「アイテムは収集されました」...
-
ピクチャボックスの座標取得
-
他アプリの操作(メニューバー)
-
Windowのちらつき防止
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
コンテキスト依存とは?
-
画面がチカチカする
-
コントロール内の文字の背景色
-
ダイアログにビットマップを貼...
-
PlgBltでの透過
-
メモリデバイスコンテキスト&...
-
Active Basic 再描写処理
-
パレット番号で塗りつぶし
-
PrintScreenしたあとに画像を保...
-
ビットマップ(表示速度とサイズ)
-
SetWindowRgn()関数について。
-
OpenGLでウィンドウハンドルの取得
-
VC++のTextOutの再描画の仕方
-
usbデバイスとの通信
-
クライアント領域をCBitmapに取...
-
ハードコピーをプログラムから...
-
[Active Basic]BitBltで画像を表示
-
BitBlt関数について教えてください
-
色描画
-
VC++でopenGLを利用したい...。
おすすめ情報