[Win32API]ダブルバッファと描画が上手にできません…

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
keito
記事: 33
登録日時: 3年前

[Win32API]ダブルバッファと描画が上手にできません…

#1

投稿記事 by keito » 2年前

こんにちは、またまたWin32APIに関する質問です。
ダブルバッファリングを実装しましたが他のサイトを参考にしても思うように描画が上手くいかなくなります。

今回のプログラムは練習としてマウスカーソルの位置に合わせて文字を表示・移動させるプログラムを作っていますが
実際にマウスを動かしたりウィンドウを最大化すると画像のように前に描画したものが残ってしまいます…
画像

とりあえず今回やりたいことは以下の通りです
(1)前に描画したものがマウスの移動の後に残らないようにする
(2)ウィンドウサイズは変更可能にする。ドラッグや最大化してもダブルバッファリングの処理が上手くいくようにする

コード:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	static HBITMAP  hBitmap;    // ビットマップ
	static HDC      hMemDC;     // オフスクリーン  
	static RECT cRect;			//クライアント領域の四隅の座標
	static HDC hDC;
	static int xpos, ypos;
	static LPCTSTR str = _T("あのイーハトーヴォのすきとおった風");

	switch (message)
	{
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
	}
	break;
	case WM_CREATE:
		//DCコンパチブルの作成
		hDC = GetDC(hWnd);
		hMemDC = CreateCompatibleDC(hDC);
		GetClientRect(hWnd, &cRect);
		hBitmap = CreateCompatibleBitmap(hDC, cRect.right - cRect.left, cRect.bottom - cRect.top);
		SelectObject(hMemDC, hBitmap);
		ReleaseDC(hWnd, hDC);
		break;
	case WM_MDIMAXIMIZE:
		hDC = GetDC(hWnd);
		hMemDC = CreateCompatibleDC(hDC);
		GetClientRect(hWnd, &cRect);
		hBitmap = CreateCompatibleBitmap(hDC, cRect.right - cRect.left, cRect.bottom - cRect.top);
		SelectObject(hMemDC, hBitmap);
		ReleaseDC(hWnd, hDC);
		break;
	case WM_MOUSEMOVE:
		xpos = LOWORD(lParam);
		ypos = HIWORD(lParam);
		InvalidateRect(hWnd, NULL, TRUE);
	case WM_PAINT:
		PAINTSTRUCT     ps;
		// DCコンパチブルの描画
		hMemDC = BeginPaint(hWnd, &ps);
		//何かしらの描画
		TextOut(hMemDC, xpos, ypos, str, _tcslen(str));
		BitBlt(hDC, 0, 0, cRect.right - cRect.left, cRect.bottom - cRect.top, hMemDC, 0, 0, SRCCOPY);		
		EndPaint(hWnd, &ps);
	break;
	case WM_ERASEBKGND:
		return TRUE;
	case WM_CLOSE:
		// DCコンパチブルの破棄
		DeleteDC(hMemDC);
		DeleteObject(hBitmap);
		DestroyWindow(hWnd);
	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
(もしよかったら「ここのコード要らないよ」とか「ここ〇〇に書き換えるといいよ」とかあったらそれも教えてもらえるとありがたいです)
どうかよろしくお願いします……!!

なお今の所の私の能力は
C/C++:入門書程度ならさっと理解できる
Win32API:今頑張ってるところ!
です(´・ω・`)

アバター
usao
記事: 1565
登録日時: 6年前

Re: [Win32API]ダブルバッファと描画が上手にできません…

#2

投稿記事 by usao » 2年前

hMemDC,hDC, hBitmap あたりの
生成と破棄のタイミングがちゃんと整理できていないのではないでしょうか.
(WM_PAINT時のhDCとかどうなってるのか?)

ISLe
記事: 2645
登録日時: 9年前
連絡を取る:

Re: [Win32API]ダブルバッファと描画が上手にできません…

#3

投稿記事 by ISLe » 2年前

恒久的なBitmapはDIBが良い。
DIBであればデスクトップの画面モードが変更されても作り直す必要がない。
(DDBだとデスクトップの状態が変化すると描画されなくなる可能性がある)
CreateDIBSection関数を使ってDIBを作成しビットマップハンドルを得る。

BitBltは、転送先と転送元のDCが逆。
hDcSrc,hDcDstといった変数名を使って転送元と転送先を明確に区別すると間違いに気付きやすくなるはず。

CreateCompatibleDCは、描画の直前に呼び出し、そこで取得したDCはすぐに破棄する。
デスクトップはいつ変化するか分からないので、ライフサイクルは短く。
BitBltの際にビットマップの選択が必要。

WM_MDIMAXIMIZEはMDIウィンドウで使われるメッセージなのでシングルウィンドウでは意味がない。
WM_SIZEを使えば、サイズ変更の理由に寄らず(最小化は除外)処理できる。


個人的にはDefWindowProcを最後に置くのが良いと考える。
戻り値の意味はメッセージによりけりなので、例え0が共通に扱われるとしてもメッセージごとに意味は異なるはずだから。

アバター
へにっくす
記事: 628
登録日時: 7年前
住所: 東京都

Re: [Win32API]ダブルバッファと描画が上手にできません…

#4

投稿記事 by へにっくす » 2年前

WM_MOUSEMOVEのあとにbreak;文がないからWM_PAINTのところに行きますね。
BeginPaint、EndPaintはWM_PAINTメッセージが来た時にだけ有効です。
間違ってもWM_MOUSEMOVEのときは使っちゃいけません。
BeginPaint
まずそこをどうにかしましょう。
written by へにっくす

アバター
usao
記事: 1565
登録日時: 6年前

Re: [Win32API]ダブルバッファと描画が上手にできません…

#5

投稿記事 by usao » 2年前

非表示エリア
この非表示エリアを表示するには、登録し、ログインする必要があります。

返信

“C言語何でも質問掲示板” へ戻る