Solved

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

Posted on 2007-11-28
10
431 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 

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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Change to event 1 138
WPF issue with Trigger 2 148
C++ mouse_event mouse look 7 131
How to measure current at integrated circuit (IC) power pin using Current Probe ? 6 77
This article will show, step by step, how to integrate R code into a R Sweave document
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
This video teaches viewers about errors in exception handling.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

739 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