Search code examples
c++windowsbitmapgdi

How to translate a simple bitmap in GDI


I want to be able to move an image across the screen. This is the code I have that displays the image, but it always displays the image starting at the origin.

void drawBitmap(HDC hdc, int x1, int y1, int x2, int y2, LPWSTR path) {
    HBITMAP bmp = (HBITMAP)::LoadImage(NULL, path, IMAGE_BITMAP, SCREEN_WIDTH, SCREEN_HEIGHT, LR_LOADFROMFILE);
    HGDIOBJ B1 = CreatePatternBrush(bmp);
    SelectObject(hdc, B1);
    Rectangle(hdc, x1, y1, x2, y2);
    DeleteObject(B1);
}

Thank you Barmak Shemirani for the answer. For anyone curious about what my code looks like now, I have replaced the original code with code from the guy that answered my question and it now looks like this:

HBITMAP hbitmap = (HBITMAP)LoadImage(NULL, path, IMAGE_BITMAP, x2-x1, y2-y1, LR_LOADFROMFILE);
HDC memdc = CreateCompatibleDC(hdc);
SelectObject(memdc, hbitmap);
BitBlt(hdc, x1, y1, x2, y2, memdc, 0, 0, SRCCOPY);
DeleteDC(memdc);

Solution

  • Create a child window and override WM_NCHITTEST to return HTCAPTION, this will cause the the child window to move around main window when it is clicked.

    Next, just draw the bitmap in child window

    #include "windows.h"
    
    LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
    {
        if (msg == WM_DESTROY)
        {
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    LRESULT CALLBACK bitmapProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
    {
        if (msg == WM_NCHITTEST)
        {
            return HTCAPTION;
        }
    
        if (msg == WM_PAINT)
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
    
            RECT rc;
            GetClientRect(hwnd, &rc);
            HBITMAP hbitmap = (HBITMAP)LoadImage(NULL, L"c:\\test\\test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    
            HDC memdc = CreateCompatibleDC(hdc);
            HBITMAP saveOldBitmap = (HBITMAP)SelectObject(memdc, hbitmap);
            BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
    
            SelectObject(memdc, saveOldBitmap); //add this
            DeleteObject(hbitmap); //*** add this, important
            DeleteDC(memdc);
    
            EndPaint(hwnd, &ps);
        }
    
        return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
    {
        WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        wcex.hInstance = hInstance;
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
        wcex.lpszClassName = L"mainWnd-bitmapWnd";
        wcex.lpfnWndProc = wndProc;
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(0, L"error 1", 0, 0);
        }
    
        HWND hmain = CreateWindow(wcex.lpszClassName, L"w32", WS_CLIPCHILDREN | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 300, 200, 0, 0, hInstance, 0);
    
        wcex.lpszClassName = L"bitmapWnd";
        wcex.lpfnWndProc = bitmapProc;
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(0, L"error 2", 0, 0);
        }
    
        CreateWindow(wcex.lpszClassName, L"w32", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 0, 50, 50, hmain, 0, hInstance, 0);
    
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int)msg.wParam;
    }
    

    change the X/Y position in BitBlt to print the bitmap in a different location