I have the following code that is supposed to paint picture2.bmp
after the user invokes the item ID_FILE_32771
.
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_FILE_32771:
hdc = BeginPaint(hWnd, &ps);
LoadAndBlitBitmap2(__T("D://picture2.bmp"), hdc);
EndPaint(hWnd, &ps);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);
EndPaint(hWnd, &ps);
break;
The problem is, nothing is getting painted. hdc
is not properly initialized. What am I doing wrong, and how do I fix it?
The BeginPaint
and EndPaint
functions are only to be called when you handle the WM_PAINT
message. The way you've done it, in handling WM_COMMAND
, is wrong:
case ID_FILE_32771:
hdc = BeginPaint(hWnd, &ps); // WRONG, WRONG!
LoadAndBlitBitmap2(__T("D://picture2.bmp"), hdc);
EndPaint(hWnd, &ps); // ALSO WRONG!
break;
All of the painting code needs to be inside of the WM_PAINT
handler. You are going to receive WM_PAINT
messages whenever you window needs to be painted, and sometimes that's outside of your control. So there needs to be logic in the WM_PAINT
handler that knows what to paint based on the current state of the application.
In other words, you need to set a flag in response to clicks on ID_FILE_32771
so that your program knows it should be calling LoadAndBlitBitmap2
when it repaints itself, instead of LoadAndBlitBitmap
(why aren't they the same function, to which you simply pass different file names?).
Outside of the WM_PAINT
handler, you cause a paint event to occur by invalidating the contents of your window. The simplest and most generally appropriate way to do that is by calling the InvalidateRect
function. For example:
case ID_FILE_32771:
// Set a flag indicating that picture2 should be painted
// (or some other equivalent mechanism)
paintPicture2 = true;
// Signal that the window should be repainted.
InvalidateRect(hWnd, NULL, TRUE);
break;
By calling UpdateWindow
after InvalidateRect
, you'll force an immediate repaint, but this is rarely necessary. Alternatively, you can skip the two-function-dance and call the more powerful RedrawWindow
function directly.
Either way, you'll invoke your WM_PAINT
message handler, and it will query the application's current status and paint the appropriate picture.
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Paint the appropriate thing, depending on the app's current state
if (paintPicture2)
LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);
else
LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);
EndPaint(hWnd, &ps);
break;