CStatic control flicker only when running with Windows Classic theme
I'm dealing with a very weird visual bug. Let me explain.
I have a C++/MFC application that displays a count in a window:
The count (text) is displayed via a `CStatic` control. The mechanism is very simple. I call it every 1000 ms and update the text as such:
Code:
void CTestCountdownFlickerDlg::RedrawCounter(LPCTSTR pText)
{
CStatic* pTxtBox = (CStatic*)this->GetDlgItem(IDC_STATIC_COUNTER);
ASSERT(pTxtBox);
//Get previous text
CString strPrevText;
pTxtBox->GetWindowText(strPrevText);
//Update only if different
if(strPrevText.Compare(pText) != 0)
{
//Set next text
pTxtBox->SetWindowText(pText);
}
}
What happens is that the `CStatic` control updates without any issues on the OS with visual themes enabled, but if I run it on the OS with the Windows Classic theme (for instance, the screenshot above is from Windows 7) the `CStatic` control produces a visible flicker every time it updates the text.
Well, I understand that I'm nitpicking here, still I would really like to get rid of this flicker.
Here's what I tried:
1. In my actual project I tried subclassing the `CStatic` control and removed the processing of `WM_ERASEBACKGROUND` by simply returning 1. That didn't help.
2. In the same subclass for `CStatic` control I tried to override `WM_PAINT`, but that didn't work at all. So I'm not sure if I'm going too far with it at this point.
I'm attaching the C++/MFC source code for my test project I made the screenshot above for.
Re: CStatic control flicker only when running with Windows Classic theme
hYou could change your design placing the "count number" in another static control and then update only this one.
Or you could replace the static control with a read-only edit one and then use CEdit::SetSel / CEdit::ReplaceSel to only replace the "count number" in the text.
Re: CStatic control flicker only when running with Windows Classic theme
Rather than call GetDlgItem on each timer click, why not use a DDX CString variable? Also no need to over-optimize by calling GetWindowText when the text is always going to need updating. Eliminating these two calls may reduce the flickering.
Re: CStatic control flicker only when running with Windows Classic theme
Thank you guys. Since I posted this question I was able to resolve it (the hard way.) I ended up making it an owner-drawn static control (by setting the SS_OWNERDRAW style) and then doing my own rendering in WM_DRAWITEM and by eliminating WM_ERASEBACKGROUND (by simply returning 1 from it.) The flicker is produced because of a two-stage drawing process: first, the background is erased while processing the WM_ERASEBACKGROUND notification, and then the actual rendering is done in the WM_PAINT notification. I don't know why they went with this method in the first place? Probably due to slow computers of the time. In this day and age such separation is totally outdated. So I think it is optimized by the OS when the modern themes are enabled, but that optimization is suppressed when "Windows Classic" is enabled, which in turn produces the flicker. So the bottom line, rendering the static control on my own is not fun (one needs a lot of code) but it fixes the issue in the first place, once the control is rendered in one place.
Re: CStatic control flicker only when running with Windows Classic theme
The inherent problem is that of "on demand painting".
In the last few instances of windows you may have come accustomed to a "new" way of painting and that is one where windows keeps a current bitmap of the application and the desktop manager uses that bitmap for creating the thumbnails in the task bar, the 3D window flipper and for composing the desktop with alpha transparencies.
You can disable that and then the old bahaviour returns, where each update causes a WM_PAINT and this in turn causes each window to paint in turn.
The flicker you see is not really caused by the static control, rather, it's being cause by the dialog painting it's client area in the 3D color prior to painting it's children.
you can fix this, but "does it really matter". If this is really such a big deal, then the suggestion by Victor is probably a better one. Leave the text as is, have the counter in a separate control. It won't remove flicker entirely, but it may limit it enough to not make it an issue anymore.
Re: CStatic control flicker only when running with Windows Classic theme
Originally Posted by OReubens
The flicker you see is not really caused by the static control, rather, it's being cause by the dialog painting it's client area in the 3D color prior to painting it's children.
So, maybe WS_CLIPCHILDREN parent style is the solution?
Re: CStatic control flicker only when running with Windows Classic theme
WS_CLIPCHILDREN... note that you need to set this on the dialog, not the control.
Maybe, but then you'll have to provide your own background which may introduce the flicker again. And it may cause other painting issues, especially if your dialog or controls are sizable.
As I said before, typically speaking "don't worry about this". If the flicker is really that much of an issue, then you should really consider a window with a custom paint rather than trying to "fix" a dialog.
THe problem with trying to "fix" dialogs is that they're used in all kinds of different modes and there are things like Terminal server, RDP, Remote desktop, Desktop composition, video drivers (accelerators), screen readers, disability services etc that will "mess up" if you try to "fix" too much. SO you may end up fixing the flicker, and introducing a bunch of other problems on another PC with another Windows setup. (that and the fact it's a lot of work to achieve little )
Re: CStatic control flicker only when running with Windows Classic theme
Originally Posted by OReubens
[...]
THe problem with trying to "fix" dialogs is that they're used in all kinds of different modes and there are things like Terminal server, RDP, Remote desktop, Desktop composition, video drivers (accelerators), screen readers, disability services etc that will "mess up" if you try to "fix" too much. SO you may end up fixing the flicker, and introducing a bunch of other problems on another PC with another Windows setup. (that and the fact it's a lot of work to achieve little )
Sounds like "it has no much sense to build as long as one day, an asteroid will hit Earth..."
Of course, the solution #2 (placing the count number in another static) is generally more kosher.
However, in this particular case, #5 (by handling WM_CTLCOLOR), although as I said is a little bit tricky, works as well. Except case someone wise has the brilliant idea to make sizeable a poor static text control, intended just to display a counter.
BTW. Just for curiosity and for fun, here is tested on a remote desktop connection. Both server (Windows Server 2012) and client (Windows 7) are hosted in virtual machines. Pretty hard conditions, isn't it?
As expected, no blinking, no flicker and no any other catastrophic issue happened...
Re: CStatic control flicker only when running with Windows Classic theme
Originally Posted by ovidiucucu
Sounds like "it has no much sense to build as long as one day, an asteroid will hit Earth..."
heh.
Not what I was trying to convey. More as in. Use windowsfeatures the way they're intended, and accept that some things work the way they do.
Yes you can fix some minor issues, but don't take it too far. I've seen a lot of apps mess up by making dialogs and certain controls do things they weren't intended, and they fail horribad on the next version of windows that did things slightly different or need massive rework for the next UI change.
and btw. asteroids hit earth EVERY DAY !
Luckily usually too small to do more damage than a small dent in a plate of pudding. But even fist to football sized asteroids hit earth regularly.
* 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.