Solved

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

Posted on 2007-11-28
10
426 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
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.

815 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

11 Experts available now in Live!

Get 1:1 Help Now