i put an image on form with WM_PAINT message.
but the image is, only, showed after resize(for example) the form. why is that? did i forget any style\extended style?

2 Years
Discussion Span
Last Post by cambalinho

in form class:

case WM_PAINT:
                    if (inst->Paint==NULL) break;
                    PAINTSTRUCT  ps;
                    HDC hdc = BeginPaint(inst->hwnd, &ps);
                    EndPaint(inst->hwnd, &ps);

(inst is the instance class pointer, but the problem is other)
the inst->Paint() is a lambda function.
heres the form instance code:

form a;
button c,g,b;

HBITMAP bmpSource = NULL;
HDC hdcSource = NULL;

int WinMain()

    a.Paint=[](HWND hwndWindow, HDC hdcWindow)
        bmpSource = (HBITMAP)LoadImage(NULL, "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        hdcSource = CreateCompatibleDC(GetDC(0));
        SelectObject(hdcSource, bmpSource);
        BitBlt(hdcWindow, 0, 0, 500, 500, hdcSource, 0, 0, SRCCOPY);


i can't see any problem with code...
but for see the paint image, i need resize(for exemple) the form... why?


The problem with the above code is actually that you LOAD the image every single time the window is painted. This can take time to do. Not only that, you never delete the compatible dc or bitmap that you created and so you are leaking in the above code. It could be that you are also doing other resource intensive code in the paint or resize messages.

Is your image not drawing at all? Is it flickering?

Other than that, I cannot replicate it.

This works just fine for me:

class Form2 : public BaseForm
        std::function<void(HWND, HDC)> onPaint;

        Form2(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent = NULL);
        LRESULT WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
        int Show();
        HWND GetHWND() {return BaseForm::GetHWND();}

        void setPaintListener(const std::function<void(HWND, HDC)>& onPaint) {this->onPaint = onPaint;}

Form2::Form2(const char *Title, POINT Location, unsigned short Width, unsigned short Height, HWND Parent)
    BaseForm::Create(0, Title, WS_OVERLAPPEDWINDOW | WS_TABSTOP, Location, Width, Height, Parent);

LRESULT Form2::WinProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
        case WM_PAINT:
            PAINTSTRUCT ps = {0};
            HDC hdc = BeginPaint(Hwnd, &ps);

            if (onPaint)
                onPaint(Hwnd, hdc);

            EndPaint(Hwnd, &ps);

        case WM_DESTROY:
            return 0;

            return DefWindowProc(Hwnd, Msg, wParam, lParam);
    return 0;

int Form2::Show()
    MSG Messages = {0};
    ShowWindow(this->GetHWND(), SW_SHOW);

    while(GetMessage(&Messages, NULL, 0, 0))
    return Messages.wParam;

int main()
    Form2 f("Hello", {CW_USEDEFAULT, CW_USEDEFAULT}, 500, 500);

    //Load the image once.. you can do this in WM_CREATE if you want.
    HBITMAP hbmp = (HBITMAP)LoadImage(GetModuleHandle(NULL), "C:/Users/Brandon/Desktop/test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    f.setPaintListener([&](HWND hwnd, HDC hdc){
        BITMAP bitmap;
        HDC hdcMem = CreateCompatibleDC(hdc);
        HGDIOBJ old = SelectObject(hdcMem, hbmp);

        GetObject(hbmp, sizeof(bitmap), &bitmap);
        BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
        SelectObject(hdcMem, old);

    int res = f.Show();
    DeleteObject(hbmp); //DELETE the loaded image.. You can do this in WM_DESTROY if you want.
    return res;

Edited by triumphost

Votes + Comments
thanks anyway

i, now, understand why don't works ;)
see my form window procedure:

static LRESULT CALLBACK WndProcForm(HWND HandleWindow, UINT msg, WPARAM wParam, LPARAM lParam)
            static POINT PreviousLocation, Location;
            static bool Tracking = false;
            static MouseButtons MBButtons;
            static bool blControl = false;
            static bool blShift = false;
            static bool blResize = false;
            static int xPos = 0;
            static int yPos = 0;
            static UINT_PTR timerid;
            static bool blnDrag = false;
            static bool KeyPressed=false;
            static int KeyDownCount=0;
            form *inst = (form *)GetWindowLongPtr(HandleWindow, GWLP_USERDATA);

            if(inst!=NULL && inst->Create!=NULL && IsWindowVisible(inst->hWnd())==true)
                static bool i=true;
                    inst->Create(inst->getLeft(), inst->getTop());
                    int a=GetLastError();
                    if (a!=0)

            if(inst!=NULL && inst->Paint!=NULL)
                 static bool i=true;

            HBRUSH g_hbrBackground = NULL;

            //Working with messages
                case WM_NCCREATE:
                    CREATESTRUCT *p = (CREATESTRUCT *)lParam;
                    inst = (form *)p->lpCreateParams;
                    SetWindowLongPtr(HandleWindow, GWLP_USERDATA, (LONG_PTR)inst);
                    inst->hwnd = HandleWindow;

the WM_PAINT message don't call my Paint() lambda, because, when i create the lambda, the Paint() is NULL. only works fine, because when we resize the form, the Paint() is called.
so i did that 2 'if': 1 for the Create() and another for the Paint()... but needs more work :(
anotherthing that i had tested too: if i do a constructor for recive the Paint(), it will works fine ;)

Edited by cambalinho


i resolve the problem adding these line:

ShowWindow(hwnd, SW_NORMAL);
InvalidateRect(hwnd,NULL,true);//i add these line for fix that

after create the form.
thanks for all

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.