How can i minimize flicker of a bitmap blitted to awindow in API code (not MFC)

Hi,
I have searched for ages trying to find a way to remove the flicker from a bitmap, rendered into a window with the below code (it is rendered on a WM_PAINT message within an owner-drawn tab control. It works but flickers really badly when resizing the window. I have tried returning false on WM_ERASEBKGND in both the main wndproc and the tab controls proc too, but its still rubbish. I read about the CMemDC, but my app is API, not MFC. Can anyone help?
Much appreciated,
DumbMonkey.
VOID CImage::Draw(HWND hWnd, LPRECT rect)
{
hDC = GetDC(hWnd);
    hCompatibleDC = CreateCompatibleDC(hDC);
    hOldBitmap = (HBITMAP) SelectObject(hCompatibleDC, hImageBitmap);
    GetObject(hImageBitmap, sizeof(imageBitmap), &imageBitmap);
    StretchBlt(hDC, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, hCompatibleDC, 0, 0, imageBitmap.bmWidth, imageBitmap.bmHeight, SRCCOPY);
    SelectObject(hCompatibleDC, hOldBitmap);
    DeleteDC(hCompatibleDC)
}

Open in new window

DumbMonkeyAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
wizrrConnect With a Mentor Commented:
Maybe you should not call default WndProc on WM_ERASEBKGND message? Just catch WM_ERASEBKGND and do not put it in DefaultWndProc.

Maybe somewhere in your WM_PAINT Clear(BRUSH_WHITE) or something?

Try to paint only changed region.
0
 
jgordosCommented:
There are several things I would try...

    HDC memDC = CreateCompatibleDC ( hDC );
    HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
    SelectObject ( memDC, memBM );

So, the DC you pass to the CreateCompatibleBitmap can be either the screen DC, or the memory DC.  When you create it using the memory DC, select your color bitmap into it, so it has the same basic layout as the screen.

The other things I'd do, if it's constantly flashing and such, are
1) use a tool like WinSpy to see the messages that are being sent to the window....  This is from memory so forgive me if it's not exactly right, but the messages are like WM_RESIZE WM_PAINT WM_RESIZE WM_PAINT
Try adding the blit code you have there to the other messages, too, like the resize handler...
2) Don't constantly select the bitmaps in and out and all around... after you've selected your bitmap in there, don't put back (ie select it back) the old crapy thing we didn't care about in the first place
3) Save your CompatibleDC... you don't need to release that back all the time


0
 
itsmeandnobodyelseCommented:
>>>> It works but flickers really badly when resizing the window.
You could try to prevent from drawing while resizing. After a small delay - say 1 second - you can make a deferred drawing of the image.

One method to solve that like that is to have a handler for WM_SIZING  (not WM_SIZE) message. WM_SIZING is sent *prior* to drawing. In the handler you set a bool member of the CImage class, e. g.  'm_isSizing' to 'true' and update the CImage::Draw by

VOID CImage::Draw(HWND hWnd, LPRECT rect)
{
      if (m_isSizing)
      {
             // put her your current drawing code
      }
}

With that there is one problem left how to reset the m_isSizing to false after the sizing ended. That can be done by setting up a timer when setting the m_isSizing to true

void CMyDialogOrView::OnSizing()
{
       if (!m_imageCtrl.m_isSizing)  // do it only once
       {
            m_imageCtrl.m_isSizing = true;
            SetTimer(99, 1000);
       }
}

That invokes a timer with the id = 99 and a period of 1 second. You can catch it by writing a handler for the WM_TIMER message:

   void CMyDialogOrView::OnTimer(UINT eventId)
   {
         if (eventId == 99)
         {
                m_imageCtrl.m_isSizing = false;
                KillTimer(99);
         }
   }

So, That would prevent from flickering at least the first second.

But, as you would get more than one WM_SIZING message if the user continues sizing the 'game' would go on and you'll got a refresh of the image only for every second. That should be fine but you can play with the timeout parameter to improve the behavior. You also could have a handler for the WM_SIZE message (you'll get after sizing) and save the current timestamp in a further member. Then the OnTimer could check how much time was elapsed since the last WM_SIZE and can decide whether to allow drawing based on that.

Regadrs, Alex

 
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
itsmeandnobodyelseCommented:
>>>> VOID CImage::Draw(HWND hWnd, LPRECT rect)
>>>> {
>>>>      if (m_isSizing)

Of course it has to be

       if (!m_isSizing)


0
 
jgordosCommented:
uh, he's not MFC...

And i think he needs the image to blit during the resize, although he really doesn't say that.

0
 
DumbMonkeyAuthor Commented:
Hi,
Yes jgordos, thats exactly what i want to do, it looks terrible when the window is resized.
Thanks all.
0
 
DumbMonkeyAuthor Commented:
Thanks all,
To fix the problem i just returned FALS to the WM_ERASEBKD. It didnt work originally as I had to do this in both the main WndProc and the tab controls WndProc. That fixed it. Thanks to jgordos for the good advice too.
0
 
wizrrCommented:
DumbMonkey what you actually did to solve this problem?
0
 
DumbMonkeyAuthor Commented:
Hi wizrr,
Well i just returned FALSE to WM_ERASEBGND. It was failing as I was doing the blitting from another wndproc (belonging to the tab control). So i added the WM_ERASEBKGND: return FALSE for both wndprocs and it worked.
Cheers,
DumbMonkey
0
 
wizrrCommented:
Thanks DumbMonkey. And good luck)
0
All Courses

From novice to tech pro — start learning today.