Solved

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

Posted on 2007-11-28
10
424 Views
Last Modified: 2012-06-27
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

0
Comment
Question by:DumbMonkey
  • 3
  • 3
  • 2
  • +1
10 Comments
 
LVL 3

Accepted Solution

by:
wizrr earned 125 total points
ID: 20367788
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
 
LVL 11

Expert Comment

by:jgordos
ID: 20367804
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20367898
>>>> 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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20367911
>>>> VOID CImage::Draw(HWND hWnd, LPRECT rect)
>>>> {
>>>>      if (m_isSizing)

Of course it has to be

       if (!m_isSizing)


0
 
LVL 11

Expert Comment

by:jgordos
ID: 20368304
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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:DumbMonkey
ID: 20368773
Hi,
Yes jgordos, thats exactly what i want to do, it looks terrible when the window is resized.
Thanks all.
0
 

Author Closing Comment

by:DumbMonkey
ID: 31411444
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
 
LVL 3

Expert Comment

by:wizrr
ID: 20369622
DumbMonkey what you actually did to solve this problem?
0
 

Author Comment

by:DumbMonkey
ID: 20370140
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
 
LVL 3

Expert Comment

by:wizrr
ID: 20370157
Thanks DumbMonkey. And good luck)
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Navigation is an important part of web design from a usability perspective. But it is often a pain when it comes to a developer’s perspective. By navigation, it often means menuing. This is less theory and more practical of how to get a specific gro…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now