简体   繁体   中英

Correct method for redrawing a layered window

I have a window created with the WS_EX_LAYERED window style. I am currently drawing onto a memory bitmap using GDI+, and using UpdateLayeredWindow to update the graphical content of my layered window. I intend to use this window as the main window of my application, which would require it to redraw frequently.

Seeing as layered windows do not receive the WM_PAINT windows message [?] , I need to come up with an appropriate method for re-drawing the window. Optimisation is not essential , but it's always nice to have your cake and eat it too. Therefore, I am in search of the "correct" method to use.

Here are my thoughts so far:

  • I would guess that it's a good idea to render onto an off-screen bitmap before BitBlt ing or similar.

  • 60 frames rendered per second should be (more than?) enough (but how does this compare to other applications' frame rates?).

Possible solutions:

  • Use SetTimer to send the WM_TIMER message on a regular basis.

    • Useful because through specifying the time-out value, I can achieve my desired frames per second, without the requirement to measure the duration a "frame" takes to be rendered.

    • Would likely cause input or other lags due to the frequency and speed of the messages.

  • Render frames only when particular events occur, such as a window resize.

    • Would require me to figure out all events that would require a redraw.

    • Would greatly reduce the amount of unnecessary frames being rendered.

  • Render frames when there are no messages in the message queue, by checking PeekMessage .

    • This might slow down the processing of window messages.

    • This will cause a high CPU usage because more frames than necessary are being processed.

  • Create a new thread to perform the render loop.

    • Timing calculations will have to be performed in order to maintain a steady frame-rate.

Layered windows don't receive WM_PAINT messages that would otherwise be generated after window visibility changed, but it won't prevent them to receive this message at all.

You can continue to use InvalidateRect to change window update region, wait for WM_PAINT in you window procedure, draw contents in bitmap and call UpdateLayeredWindow to change window contents. You can use this method to request redraw when content of window changes, for example, when button was pressed, or window has been resized (or activated/deactivated).

It shouldn't be so complicated, this is the pseudo code for you message loop:

while (true) 
{
    // GetMessages
    while (PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE))
    {
        if (!GetMessage(&msg, hWnd, 0, 0 ))
        {
            // Need to handle WM_QUIT
            ...
            break;
        }
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    // Check if we need to draw
    if (TimeForANewFrameHasCome() ||
        IfWeNeedToDrawAfterInputOrInvalidate() ||
        AnyOtherCaseThatCausesAnUpdate())
    {
         // Render
         UpdateMemoryDCOrBitmap(...);

         // Display it
         UpdateLayeredWindow(...);
    }

    // May sleep a while
    // Either Sleep(20); or better MsgWaitForMultipleObjects, that makes it possible
    // to wake up upon an Event too... 
    MsgWaitForMultipleObjects(...);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM