ビットマップに描画


DC互換ビットマップを作る

前回、モノクロビットマップの作成に成功しました
次は、ディスプレイに互換性のあるビットマップを作成してみましょう

指定されたデバイスコンテキストと互換性のあるビットマップを作成すれば
ディスプレイに描画する方法と同様の方法で自由に描画できるようになります
これを行うには CreateCompatibleBitmap() 関数を使用します

HBITMAP CreateCompatibleBitmap(HDC hdc , int nWidth , int nHeight);

hdc には、互換性を取るデバイスコンテキストのハンドル
nWidth はビットマップの横幅、nHeight は高さを指定します
成功するとビットマップのハンドル、失敗すると NULL が返ります

nWidth と nHeight に 0 を指定した場合は 1 × 1 のモノクロビットマップを作成します
ここで取得したビットマップのハンドルをメモリデバイスコンテキストに設定し
メモリデバイスコンテキストに対し、ディスプレイと同様にグラフィック処理を行える

このような処理は、様々な恩恵を受けられます
例えばユーザーに図を描かせるプログラムの場合は、このビットマップに描画するべきでしょう
これは、もしクライアント領域に直接描画すると、無効化された時に絵が消えてしまためです
しかし、ビットマップに描画すればそんな問題は発生しません

第二に、描画処理に時間がかかる場合
その描画過程をユーザーに見せず、描画終了時に表示したほうが綺麗です
この場合も、ビットマップに描画処理を行い、最後にビットマップを描画することで実現できます
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	static HBITMAP hBitmap;
	static HDC hBuffer;

	switch (msg) {
	case WM_DESTROY:
		DeleteDC(hBuffer);
		DeleteObject(hBitmap);

		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hdc = GetDC(hwnd);

		hBitmap = CreateCompatibleBitmap(hdc , 400 , 200);
		hBuffer = CreateCompatibleDC(hdc);

		SelectObject(hBuffer , hBitmap);
		SelectObject(hBuffer , GetStockObject(NULL_PEN));

		PatBlt(hBuffer , 0 , 0 , 400 , 200 , WHITENESS);
		
		ReleaseDC(hwnd , hdc);
		return 0;
	case WM_MOUSEMOVE:
		if (GetKeyState(VK_LBUTTON) < 0) {
			SelectObject(hBuffer , CreateSolidBrush(0xFF));
			Ellipse(	hBuffer , 
				LOWORD(lp) - 2 , HIWORD(lp) - 2 ,
				LOWORD(lp) + 2 , HIWORD(lp) + 2
			);
			DeleteObject(SelectObject(
				hBuffer , GetStockObject(WHITE_BRUSH)
				)
			);
			InvalidateRect(hwnd , NULL , FALSE);
		}
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd , &ps);

		BitBlt(hdc , 0 , 0 , 400 , 200 , hBuffer , 0 , 0 , SRCCOPY);

		EndPaint(hwnd , &ps);
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


マウスの左ボタンをドラッグして連続した円を描画することができます
このような処理は、マウスメッセージを理解していれば簡単に実装できますが
領域が無効化されると、図が消えてしまうという問題がありました

しかし、このプログラムはビットマップに図を描画しています
そして、クライアント領域はこのビットマップを描画します

ところで、メモリデバイスコンテキスト生成後にユーザーや別プログラムが
画面のプロパティから、ディスプレイの解像度や色数を変更してしまったらどうなるのでしょう?
メモリデバイスコンテキストとディスプレイの互換性が無くなってしまうのでしょうか?

実は、嬉しい事にこの問題はプログラムは無視して構いません
Windows はビデオモードが変更されるとメモリデバイスコンテキストの色解像度も変更します


CreateCompatibleBitmap()

HBITMAP CreateCompatibleBitmap(HDC hdc , int nWidth , int nHeight);

指定されたデバイスコンテキストに関連するデバイスと互換性のあるビットマップを作成します

hdc - デバイスコンテキストのハンドルを指定します
nWidth - ビットマップの幅をピクセル単位で指定します
nHeight - ビットマップの高さをピクセル単位で指定します

戻り値 - ビットマップのハンドル。失敗すると NULL



前のページへ戻る次のページへ