-2

I've a popup window that displays a picture. Each time it displays a picture, the content is changed by another code to make it look like a motion picture.

Without using a while loop, it just displays the picture and the window doesn't hang, it responds perfectly well.

But I'm unable to achieve what I want without a while loop. when I use the while loop to create the motion picture. It works, but after a while the window stops responding.

Here's an example of the window procedure:

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
    HDC hdc;
    PAINTSTRUCT ps;

    switch(msg){
        case WM_PAINT:{             
            hdc = BeginPaint(hWnd, &ps);
            Gdiplus::Graphics graph(hdc);
            while(true){            
                Sleep(100); 
                Image img(L"Test.png");
                graph.DrawImage(&img, 0, 0, 1000, 700);             
            }
            EndPaint(hWnd, &ps);
        }
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProcW(hWnd,msg,wp,lp);
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 2
    You can't put a loop like that inside the WM_PAINT handler, it will freeze your whole program. Instead move the logic to figure out what image to draw outside of there and inly draw the image inside the handler. You could use something like [SetTimer](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer) to handle the logic to switch to the next image. – Retired Ninja Oct 06 '22 at 01:41
  • This image is just a single image what my program does is it rewrites the byte's of the existing image with the new one that I've specified already, so definitely I'll need the while loop to make sure the window reloads the image.. I have tried using threads but it wasn't successful. – Marsha4Coding Oct 06 '22 at 02:00
  • @RetiredNinja I tried using setimer earlier Nd it still freezes!! I don't know if I placed it wrongly but it compiled and nothing changed. – Marsha4Coding Oct 06 '22 at 02:02
  • 1
    ⟼Remember, it's always important, *especially* when learning and asking questions on Stack Overflow, to keep your code as organized as possible. [Consistent indentation](https://en.wikipedia.org/wiki/Indentation_style) helps communicate structure and, importantly, intent, which helps us navigate quickly to the root of the problem without spending a lot of time trying to decode what's going on. – tadman Oct 06 '22 at 02:16
  • 3
    I can't speak to code that I can't see, but an infinite loop inside a WndProc is never going to work. Your application must continue to process messages and it can't if one of them never finishes. – Retired Ninja Oct 06 '22 at 02:16
  • 1
    You'll want to get a [book](https://www.amazon.com/dp/157231995X/), or start here: [Get Started with Win32 and C++](https://learn.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows). – IInspectable Oct 06 '22 at 06:42

1 Answers1

1

As @RetiredNinja said in comments, this code really needs a timer, not a while loop. If you block the window procedure, the window will stop responding to messages. You must return flow to the thread's message loop after each message is processed.

At startup, load your initial image, start the timer, and invalidate the window. Done.

Whenever the timer fires, update the image as needed and invalidate the window to trigger a repaint. Done.

Every time the window procedure receives a WM_PAINT message, draw the current image as-is onto the window. Done.

That is all you need to do. No threads are needed. And the app remains responsive at all times, because no single message is blocked for more than a few milliseconds.

Try something more like this instead:

Image *img = nullptr;

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
    switch(msg){
        case WM_CREATE:
            img = Image::fromFile(L"Test.png", FALSE);
            SetTimer(hWnd, 1, 100, NULL);
            break;

        case WM_DESTROY:
            KillTimer(hWnd, 1);
            delete img;
            PostQuitMessage(0);
            break;

        case WM_TIMER:{
            // update img as needed...
            InvalidateRect(hWnd, NULL, TRUE);
            break;
        }

        case WM_PAINT:{             
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            Gdiplus::Graphics graph(hdc);
            graph.DrawImage(img, 0, 0, 1000, 700);             
            EndPaint(hWnd, &ps);
            break;
        }

        default:
            return DefWindowProcW(hWnd, msg, wp, lp);
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This code was just too perfect... It worked though it was twitching at first then I changed invalidateRect to RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW) – Marsha4Coding Oct 06 '22 at 22:00
  • I appreciate your effort I'll post my code so other who might have same issues might find it helpful.. https://stackoverflow.com/questions/2325894/difference-between-invalidaterect-and-redrawwindow that's also a post I found helpful. – Marsha4Coding Oct 06 '22 at 22:01
  • @Marsha4Coding "*it was twitching at first*" - Did you try changing `TRUE` to `FALSE` in `InvalidateRect()`? It could just be the extra background repainting that is causing the twitching – Remy Lebeau Oct 06 '22 at 22:34
  • Yh your correct I didn't change TRUE to FALSE I will also check that.. – Marsha4Coding Oct 06 '22 at 22:55