CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Sep 2009
    Posts
    32

    How do I stop flickering?

    Simple question, how do I stop all this flickering going on when ever I change the size of my application?
    It affects all controls and other child windows and is probably isn't super important to fix but is really annoying :/

  2. #2
    Join Date
    Apr 2009
    Posts
    598

    Re: How do I stop flickering?

    A common cause of flickering is when the background of a window is painted again. You can avoid it in classical C programming with these three lines in your message loop:
    Code:
          case WM_ERASEBKGND:
             return(1); // Prevent erasing the background to reduce flickering
             break;

  3. #3
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: How do I stop flickering?

    Quote Originally Posted by olivthill2 View Post
    A common cause of flickering is when the background of a window is painted again. You can avoid it in classical C programming with these three lines in your message loop:
    Code:
          case WM_ERASEBKGND:
             return(1); // Prevent erasing the background to reduce flickering
             break;
    This, of course, is if you will paint your background on WM_PAINT.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  4. #4
    Join Date
    Sep 2009
    Posts
    32

    Re: How do I stop flickering?

    Quote Originally Posted by olivthill2 View Post
    A common cause of flickering is when the background of a window is painted again. You can avoid it in classical C programming with these three lines in your message loop:
    Code:
          case WM_ERASEBKGND:
             return(1); // Prevent erasing the background to reduce flickering
             break;
    It worked but my background went white instead of the grey I want it to be, although when I minimise then open my app it's back to normal. Can someone please explain why this is happening?
    Quote Originally Posted by VladimirF View Post
    This, of course, is if you will paint your background on WM_PAINT.
    So to fix it going white, I should use GDI to draw the background grey instead of doing it in my window class? Is that what you would do?

    EDIT: Tried painting background within WM_PAINT, just brought the flickering back
    Also the "WM_ERASEBKGND" doesn't seem very reliable, while mucking around resizing my window I managed to make it show my window incorrectly.

    Any other easy fixes I can do to stop the flickering? Or will I just have to live with it?
    Last edited by Waterfox; November 24th, 2009 at 02:19 AM.

  5. #5
    Join Date
    Feb 2005
    Posts
    2,160

    Re: How do I stop flickering?

    The rule is: never paint the same pixel twice. If you are erasing your background, then drawing on it, you are painting at least some pixels twice and you get flicker. You can either take elaborate steps to ensure that you only paint specific areas at specific times, but that gets complicated quick. A much easier way is to do all your drawing to memory, then when everything is done, paint the memory to the screen in one step. This is known as "double-buffering" and is accomplished in a variety of ways, but usually you just copy your device context to a memory device context, then select its bitmap to draw on, then the last step is to bitblt the memory DC's bitmap to the actual window DC.

    Here's a quick rundown (I haven't used direct API calls for this stuff for awhile so this is from memory and it might be off a bit and there's certainly room for optimization):

    Code:
      case WM_PAINT:
        {
          hdc = BeginPaint(hWnd, &ps);
    
          RECT clinetrect;
          int cx,cy;
    
          GetClientRect(hWnd,&clinetrect);
          cx=clinetrect.right-clinetrect.left;
          cy=clinetrect.bottom-clinetrect.top;
    
          HDC memdc=::CreateCompatibleDC(hdc);
          unsigned bpp=::GetDeviceCaps(hdc,BITSPIXEL); 
          HBITMAP hBmp=::CreateBitmap(cx,cy,1,bpp,NULL);    
          HBITMAP hTmpBmp=(HBITMAP)::SelectObject(memdc,(HGDIOBJ)hBmp);
          //do all your drawing here to the memdc
          ::FillRect(memdc,&clinetrect,(HBRUSH)GetStockObject(LTGRAY_BRUSH));
          ::MoveToEx(memdc,0,0,NULL);
          ::LineTo(memdc,cx,cy);
    
          //when you are done drawing, update the main DC
          ::BitBlt(hdc,0,0,cx,cy,memdc,0,0,SRCCOPY);
          ::SelectObject(memdc,(HGDIOBJ)hTmpBmp);
          ::DeleteDC(memdc);
    
    
          EndPaint(hWnd, &ps);
        }
        break;
      case WM_ERASEBKGND:
        return TRUE;

    Another problem is that you mention that you have child windows and controls. These paint themselves so you will still get flickering. You can prevent this in most cases by setting your window style to include WS_CLIPCHILDREN.

  6. #6
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: How do I stop flickering?

    You can also:
    For a main window, set class style to anything but CS_HREDRAW | CS_VREDRAW. It can be 0.
    If you are creating child window, do the same: remove CS_HREDRAW | CS_VREDRAW styles.

    No need to handle WM_ERASEBKGND.
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

  7. #7
    Join Date
    Sep 2009
    Posts
    32

    Re: How do I stop flickering?

    Quote Originally Posted by JohnCz View Post
    You can also:
    For a main window, set class style to anything but CS_HREDRAW | CS_VREDRAW. It can be 0.
    If you are creating child window, do the same: remove CS_HREDRAW | CS_VREDRAW styles.

    No need to handle WM_ERASEBKGND.
    Wow! Thanks! That works great, but why do I see it in tutorials and stuff with CS_HREDRAW | CS_VREDRAW ? Are there going to be any problems caused by doing this?

  8. #8
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: How do I stop flickering?

    If you use CS_HREDRAW and CS_VREDRAW windows class styles entire window will be redrawn when resizing, in most cases causing flicker.
    You need this behavior in some windows but in majority of cases, redrawing is undesirable.
    It absolutely has no ill effect on window behavior with the exception of desired.
    Mere fact that CS_HREDRAW and CS_VREDRAW are used in samples and tutorials does not mean you have to follow a sheep herd.
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

  9. #9
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: How do I stop flickering?

    Quote Originally Posted by JohnCz View Post
    You need this behavior in some windows but in majority of cases, redrawing is undesirable.
    I respectfully disagree.
    There are many cases where you DO need those styles:
    - if your view is scrollable
    - if you scale it when window is resized
    - if you change layout (move / resize controls)

    This basically leaves only ONE case when you don’t need them:
    - if you only show whatever part of content fits in the window and nothing changes on resize.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  10. #10
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: How do I stop flickering?

    Vlad, obviously we have difference of opinion. I also respectfully disagree,
    I did not state that we do not need background being erased in all cases, I stated in majority of cases.
    As (I think Chinese) saying goes, picture is better than a thousand words:
    I have attached 2 zip file with four different executables, illustrating your first and second use case.
    In each case suffix _E denotes CS_HREDRAW | CS_VREDRAW class style used to create view. No suffix, used 0 for a class style;

    For scalable samples I used prefix CE_

    Each use case is built using the same code, the only difference was window class style.
    Attached Files Attached Files
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

  11. #11
    Join Date
    Sep 2009
    Posts
    32

    Re: How do I stop flickering?

    I'm with JohnCz, I have 2 child windows (not inc. controls) that I set to resize when the main window is resized. I have both my main and 2 child windows with their styles set to 0 and I'm having no problems at all when I resize the main window, they're correctly resizing and not flickering at all, one of them is even rendering Direct2D and not having any problems.

  12. #12
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: How do I stop flickering?

    In addition, when resizing multiple controls, the best way to avoid any side effect is to use BeginDeferWindowPos, DeferWindowPos, EndDeferWindowPos block to resize/move windows in one atomic action.
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

  13. #13
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: How do I stop flickering?

    Quote Originally Posted by JohnCz View Post
    Vlad, obviously we have difference of opinion.
    John, I feel tricked. Or even – cheated.
    In your examples, the top level window DOES have CS_HREDRAW | CS_VREDRAW styles. Also, it doesn’t have WS_CLIPCHILDREN style.
    So any changes in size invalidate entire top level window, and all its children. Did I miss anything?
    Anyway, the purpose of the CS_HREDRAW | CS_VREDRAW styles is to invalidate entire window whenever its size changes. If these styles are not used, only the newly added / uncovered area will get invalidated. It means that when you size your window down, nothing is invalidated.
    For your app to work, you must be invalidating entire child window when its size changes. If you do it manually – you are correct, you don’t need CS_HREDRAW | CS_VREDRAW styles. But this is cheating, isn’t it? It’s like I state that I can move a plate on the table without touching it; I’ll just ask my wife to move it.
    I too would like to illustrate my point. Here is a simple Win32 app’s WM_PAINT handler:
    Code:
    case WM_PAINT:
    	{
    		PAINTSTRUCT ps;
    		HDC hdc = BeginPaint(hWnd, &ps);
    		// TODO: Add any drawing code here...
    		RECT r = {0};
    		::GetClientRect(hWnd, &r);
    		::MoveToEx(hdc, 0, 0, 0);
    		::LineTo(hdc, r.right, r.bottom);
    		EndPaint(hWnd, &ps);
    	}
    	break;
    Attached is the executable and complete project.
    You can see the drawing defects with a naked eye.
    The drawing of child controls is NOT affected by these styles, only the background of the window itself. If all your window does is to host child controls over solid background, then I agree, you don’t need these styles. (Newly added background will get painted anyway, and already painted background never changes).
    So it looks like the difference between our opinions is: what is the majority of cases?
    Attached Files Attached Files
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  14. #14
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: How do I stop flickering?

    Quote Originally Posted by VladimirF View Post
    John, I feel tricked. Or even – cheated.
    In your examples, the top level window DOES have CS_HREDRAW | CS_VREDRAW styles.
    Vladimir, I am quite taken aback by stating that I am trying to cheat or trick you. I can assure you I am not, by any stretch of imagination. Setting CS_HREDRAW | CS_VREDRAW is irrelevant for this sample. This sample was written that even if you draw using double buffering CS_HREDRAW | CS_VREDRAW introduces flickering; that is to follow OOP problem solution.
    Quote Originally Posted by VladimirF View Post
    Also, it doesn’t have WS_CLIPCHILDREN style.
    The samples I posted are all SDI applications. Actually it is one base with different class styles. I am not sure why main frame would require WS_CLIPCHILDREN style. Top windows and MDI child frames use WS_CLIPSIBLINGS style. Besides as I stated I did not change anything from odiginaly generated code, but view class style and drawing code.

    We must have different experience regarding this particular issue. I appreciate examples you have posted as well as your opinion. Nevertheless we are both entitled to have our own view. Besides, your sample illustrated single line drawing, that flickers when main window is resized.

    I am posting another example of the SDI application, where I did not do any drawing. It was created by app wizard and contains list view control. The only addition to a default code I have included is adding list items.

    See how it works and uncomment code in CMainFrame::PreCreateWindow and see the difference it makes for stopping flickering when window is resized.

    Quote Originally Posted by VladimirF View Post
    So it looks like the difference between our opinions is: what is the majority of cases?
    I came to a conclusion. We can pass samples back and forth showing different effect of using redraw classes.
    I think the difference of opinions will disappear when we agree that whatever majority of cases is, as like in real life, one has to use common sense to find the best way to resolve any flickering issue.
    Attached Files Attached Files
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

  15. #15
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: How do I stop flickering?

    Hi John, I apologize for upsetting you, didn’t mean to.
    It all looks like misunderstanding, and I blame my English language skills.
    The *ONLY* (single) point I am making is that you DO need CS_HREDRAW and CS_VREDRAW styles to invalidate the part of your window that is NOT affected by current resize operation.
    My overly simplified example draws diagonal line to emulate scaling, and it demonstrates that when you size window down - nothing gets invalidated (and consecutively painted), and when you size up - only newly added area is invalidates (and painted).
    The "trick" I complained about is that your code somehow invalidates entire child window (confirmed by the fact that it is painted all over), while you stated (in your post # 10 above) that you don't need CS_HREDRAW and CS_VREDRAW styles.
    Again, all I am saying is that somebody needs to invalidate your entire window in order for your scaled image to paint properly. This could be done for you by Windows (if you set those styles), or you can invalidate it yourself at will. And if you DO need this invalidation - why not let Windows do its job?
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured