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 :/
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;
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...
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?
Originally Posted by VladimirF
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.
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.
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.
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?
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.
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...
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.
There are only 10 types of people in the world: Those who understand binary and those who do not.
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.
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.
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?
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...
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.
Originally Posted by VladimirF
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.
Originally Posted by VladimirF
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.
There are only 10 types of people in the world: Those who understand binary and those who do not.
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...
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.