起動直後に何かを描画したい場合には、WM_CREATE メッセージの中で描画すれば良いような気がしますが、WM_CREATE メッセージの直後には、必ず WM_PAINT メッセージが発生します。
そして、デバイスコンテキストによる描画は、メッセージ間で共有されません。つまり WM_CREATE で描画したとしても、WM_PAINT メッセージでは、その描画は消えることになります。
ですから、デバイスコンテキストによる描画は、通常、WM_PAINT の中で行うことになります。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("BEGINPAINT");
RegisterClass(&wc);
hwnd = CreateWindow(TEXT("BEGINPAINT"),
TEXT("Windos API Primer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
switch (msg)
{
case WM_PAINT:
GetClientRect(hwnd, &rect);
hdc = BeginPaint(hwnd, &ps);
Rectangle(hdc,
rect.right / 2 - 10, rect.bottom / 2 - 10,
rect.right / 2 + 10, rect.bottom / 2 + 10);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
デバイスコンテキストによる描画は WM_PAINT の中で行うのが常套ですが、他のメッセージの中でデバイスコンテキストによる描画が行えると、より柔軟なプログラムが作れます。
WM_PAINT メッセージ以外のメッセージでデバイスコンテキストを取得するには、GetDC 関数を使います。GetDC 関数で取得したデバイスコンテキストは、描画が終了した後に、ReleaseDC 関数で必ず解放しなければなりません。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("GETDC");
RegisterClass(&wc);
hwnd = CreateWindow(TEXT("GETDC"),
TEXT("Windos API Primer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
int x, y;
switch (msg)
{
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
x = LOWORD(lParam);
y = HIWORD(lParam);
Rectangle(hdc, x - 10, y - 10, x + 10, y + 10);
ReleaseDC(hwnd, hdc);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
クリックで四角形を描画して、ウィンドウのサイズを変更してもその描画が残るようになれば、もっと良くなります。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("BEGINPAINT");
RegisterClass(&wc);
hwnd = CreateWindow(TEXT("BEGINPAINT"),
TEXT("Windos API Primer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static RECT rect[10000];
static int nCount = 0;
PAINTSTRUCT ps;
int i, x, y;
HDC hdc;
switch (msg)
{
case WM_LBUTTONDOWN:
x = LOWORD(lParam);
y = HIWORD(lParam);
SetRect(&rect[nCount], x - 10, y - 10, x + 10, y + 10);
hdc = GetDC(hwnd);
Rectangle(hdc,
rect[nCount].left, rect[nCount].top,
rect[nCount].right, rect[nCount].bottom);
ReleaseDC(hwnd, hdc);
nCount++;
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (i = 0; i< nCount; i++)
{
Rectangle(hdc,
rect[i].left, rect[i].top, rect[i].right, rect[i].bottom);
}
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
左クリックでは四角形を描画して、右クリックですべての四角形が消えるようにしても面白いかもしれません。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("BEGINPAINT");
RegisterClass(&wc);
hwnd = CreateWindow(TEXT("BEGINPAINT"),
TEXT("Windos API Primer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static RECT rect[10000];
static int nCount = 0;
PAINTSTRUCT ps;
int i, x, y;
HDC hdc;
switch (msg)
{
case WM_LBUTTONDOWN:
x = LOWORD(lParam);
y = HIWORD(lParam);
SetRect(&rect[nCount], x - 10, y - 10, x + 10, y + 10);
hdc = GetDC(hwnd);
Rectangle(hdc,
rect[nCount].left, rect[nCount].top,
rect[nCount].right, rect[nCount].bottom);
ReleaseDC(hwnd, hdc);
nCount++;
break;
case WM_RBUTTONDOWN:
nCount = 0;
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (i = 0; i< nCount; i++)
{
Rectangle(hdc,
rect[i].left, rect[i].top, rect[i].right, rect[i].bottom);
}
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
描画される四角形は常に一つにして、クリックした場所に四角形が移動するのも面白いでしょう。
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("BEGINPAINT");
RegisterClass(&wc);
hwnd = CreateWindow(TEXT("BEGINPAINT"),
TEXT("Windos API Primer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int x, y = -10;
PAINTSTRUCT ps;
HDC hdc;
switch (msg)
{
case WM_LBUTTONDOWN:
x = LOWORD(lParam);
y = HIWORD(lParam);
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
Rectangle(hdc, x - 10, y - 10, x + 10, y + 10);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}