Reputation:
How can I stop displaying the bitmap in my Win32 Project. I have a method that I'm calling in WM_PAINT called LoadBitmap. It's code looks like this:
bool LoadBitmap(LPTSTR szfilename, HDC winhdc, int x, int y) {
HBITMAP bitmap;
bitmap = (HBITMAP)LoadImage(NULL, szfilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (bitmap == NULL) {
::MessageBox(NULL, _T("Bitmap failed"), NULL, MB_OK);
return false;
}
HDC hdc;
hdc = ::CreateCompatibleDC(winhdc);
if (hdc == NULL)
{
::MessageBox(NULL, _T("HDC FAILED"), NULL, MB_OK);
return false;
}
BITMAP qbitmap;
int ireturn = GetObject(reinterpret_cast<HGDIOBJ>(bitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qbitmap));
if (!ireturn) {
::MessageBox(NULL, _T("RETURN FAILED"), NULL, MB_OK);
return false;
}
HBITMAP holdbitmap = (HBITMAP)::SelectObject(hdc, bitmap);
if (holdbitmap == NULL) {
::MessageBox(NULL, _T("HOLD FAILED"), NULL, MB_OK);
return false;
}
BOOL qRetBlit = ::BitBlt(winhdc, x, y, qbitmap.bmWidth, qbitmap.bmHeight, hdc, 0, 0, SRCCOPY);
if (!qRetBlit)
{
::MessageBox(NULL, _T("BLIT FAILED"), NULL, MB_OK);
return false;
}
::SelectObject(hdc, holdbitmap);
::DeleteDC(hdc);
::DeleteObject(bitmap);
return true;
}
NOTE x and y change continuously. When x and y change however, the previous instance of them stays behind.
How can I stop displaying a bitmap once it has been painted in a new position?
Upvotes: 3
Views: 900
Reputation: 31599
If there is background brush then the old bitmap is erased with each paint call. If there is no background then erase it manually for example with FillRect
Here is example with double buffering, assumes there is no background brush.
case WM_PAINT:
{
...
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
LoadBitmap(filename, memdc, x, y);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
Edit *************
It will be faster to load the bitmap file only once. For each paint request, we need only to draw the bitmap, instead of LoadImage every time + draw.
You can declare HBITMAP
handles as static values in window's procedure. Set it up once in WM_CREATE
, and clean it up in WM_NCDESTROY
. Now we can use them anywhere in side window procedure:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
static HBITMAP hbitmap_background = NULL;
static HBITMAP hbitmap_sprite = NULL;
switch (msg)
{
case WM_CREATE:
{
hbitmap_background = (HBITMAP)LoadImage(NULL,
L"background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_background)
OutputDebugStringW(L"!hbitmap_background\n");
hbitmap_sprite = (HBITMAP)LoadImage(NULL,
L"sprite.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_sprite)
OutputDebugStringW(L"!hbitmap_sprite\n");
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
//setup double-buffering:
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
DrawBitmap(hbitmap_background, memdc, 0, 0);
DrawBitmap(hbitmap_sprite, memdc, 0, 0);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCDESTROY:
{
//cleapup bitmap handles
if (hbitmap_background)
DeleteObject(hbitmap_background);
if (hbitmap_sprite)
DeleteObject(hbitmap_sprite);
}
}
return DefWindowProc(hwnd, msg, wp, lp);
}
We can change DrawBitmap
so it only needs HBITMAP
handle
void DrawBitmap(HBITMAP hbitmap, HDC hdc, int x, int y)
{
if (!hbitmap)
{
OutputDebugStringW(L"error\n");
return;
}
BITMAP bm;
GetObject(hbitmap, sizeof(BITMAP), &bm);
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbitmap = SelectObject(memdc, hbitmap);
BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbitmap);
DeleteDC(memdc);
}
Note, in this example I assume background.bmp is very large, and sprite.bmp is very small. If it is painted the other way around then background will hide the sprite.
Upvotes: 3