I have a problem with the way my scrollbars are drawn. Because of external limitations (my application being a plugin running in an external window that insists on painting over any regular child window), I have to use SCROLLBAR-class windows (as opposed to using WS_CHILD | WS_VSCROLL)
For almost every message received, the scrollbar is shown animating smoothly and consistently. However, when I receive the SB_LINEDOWN message(i.e. when I click on the bottom/right arrow), the scroll bar flickers horribly (Low-framerate example). Again, all other messages work perfectly.
I have tested removing the scrollbar position update (Still broken) and removing the actual scrolling code (Still broken). I am already double-buffering the area to prevent an even worse flickering..
What might cause this and how could I fix it?
In addition to what Goz mentioned, which I bet you're already doing, it may be worth experimenting with combinations of WS_CLIPCHILDREN and WS_CLIPSIBLINGS on the scrollbar window itself and its container or any overlapping windows.
Try intercepting and ignoring the WM_ERASEBKGND this has helped me a lot with flicker in controls. Dunno if its your problem though :(
Related
I am using the following library call to change the window to dark mode:
BOOL dark = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark));
This works, with a small caveat. The title bar doesn't update until some additional event happens, like maximizing, losing focus, resizing, etc. (but not moving the window).
I have tried UpdateWindow and a huge number of combinations of flags on RedrawWindow with no luck. How can I force the title bar to redraw?
Edit I was able to force the reset by programmatically resizing the window, then resetting it to the previous size. But that seems like a terrible method. There must be a proper solution.
I have a popup dialog( CDialog ) that handles WM_CTLCOLOR message to color itself. It is having some controls (like bitmap buttons) that draws themselves using OwnerDraw. It is also having a control that displays an image with size that takes up to 70% of the dialog.
When user re-sizes the dialog, some of the controls in the dialog should be re-positioned (not re-sized). It also involves re-sizing of the image inside the dialog. As the re-sizing of image makes the whole process slow, individual re-positioning of the controls are causing a visual effect of flickering.
I need to get rid of these. One idea is to put the controls as the children of an intermediate dialog that is the child of the original popup dialog. So, when there is a re-size, I can re-position the dialog only instead of moving each controls individually. (Re-position happens only in one direction (x or y), so moving the intermediate dialog should be enough.
As it involves some coding effort, before going this way, I need answers to the following questions:
Will this work?
If yes, whats the complexity involved in this method?
Is there a better way?
Please help!
Simple fixes are:
creating the slow window last so that it doesn't hold up drawing of the simple controls
turning on the WS_EX_COMPOSITED style flag so Windows double-buffers the entire window, including its children. Beware of painting artifacts
turning off the WS_CLIPCHILDREN style flag so the holes are not so noticeable. Making the background white would accomplish the same
keeping the drawing of slow controls simple between WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE
using less controls, burning up an expensive window on a simple string or image is unnecessary
It will probably work, but you should try solutions that don't alter your control hierarchy before, because it has other subtle consequences (focus, tab order, message notifications, etc).
Try one or all of the following:
Use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos functions to move the children.
Set the WS_CLIPCHILDREN style flag in the dialog.
Set the WS_EX_LAYERED extended style flag in the dialog.
I have a VS2008 C++ application for Windows XP SP3 developed using WTL 8.1. My application contains a tab control that flickers when the application border is resized.
My window hierarchy looks like this:
CFrameWindowImpl CMainFrm
|-CSplitterWindow Splitter
|-CTabView Configuration Tabs
| |-CDialogImpl Configuration View 1
| |-CDialogImpl Configuration View 2
| |-CDialogImpl Configuration View 3
|-CDialogImpl Control View
The solution I'm trying is to make the CFrameWindowImpl derived class use the WS_EX_COMPOSITED style and all windows beneath it use the WS_EX_TRANSPARENT style. Unfortunately, this makes the tab control buttons show as an empty black bar and the controls of any Configuration View to not show at all.
If I remove the WS_EX_COMPOSITED and WS_EX_TRANSPARENT styles, the form displays properly, but the CTabView and everything beneath it flickers horribly when resized.
What do I need to change to eliminate the flicker and draw the controls properly?
Thanks,
PaulH
Edit:
Got it working. I removed all the WS_EX_TRANSPARENT styles per Mark Ransom's suggestion. I put the WS_EX_COMPOSITED style on only the CTabCtrl (contained within the CTabView). Other controls get double-buffering as needed through WTL::CDoubleBufferImpl<>.
A window flickers because it gets erased before it's drawn. To eliminate this you need to disable erasing of the window entirely and use double buffering - draw the window contents into a bitmap, then copy the bitmap to the window. Because the bitmap contains the entire contents including the background, there's no need to erase anymore.
It looks like WS_EX_COMPOSITED will handle the double buffering automatically, but you still probably need to use a NULL background brush and/or handle the WM_ERASEBKGND message.
Whats not mentioned in MSDN is that the Desktop Window Manager - the component that hooks window painting on Windows Vista and 7 to perform the desktop composition necessary to get the aero glass effect - does NOT implement WS_EX_COMPOSITED.
Which means all the work you put into getting this style to work on XP, is doomed to become irrelevent on Vista or later.
The other problem with WS_EX_COMPOSITED - and why it was an optional style and not a default on XP: The double buffering only picks up painting performed during the BeginPaint / EndPaint block of the parent window. Lots of, even standard controls, perform painting outside of their WM_PAINT handlers, and as a result the backbuffer gets only partially painted.
Sadly, the result is, the only way to "eliminate" flicker in native API apps is to try to minimize it: WS_CLIPCHILDREN and WS_CLIPSIBLINGS can help if you dont have overlapping controls - to ensure that each control's area is painted only once. And ensure that the main dialog does not perform any flood filling in WM_ERASEBKGND
It is not, in my experience, possible to use double-buffering for anything that contains child controls (unless they all fully support WM_PRINT, which most do not).
Group boxes don't render properly if the parent window has the WS_CLIPCHILDREN style set. My current workaround is to simply remove the flag from the parent. However this results in extreme flickering when resizing the window.
Is there a better workaround possible?
Update
The Dr Dobbs article Resizable Dialogs Revisited address exactly the same problem that I am experiencing. The solution offered reduces flashing, but doesn't eliminate it. I'll be using this code. However if better solutions would be possible, then feel free to post them!
Don't use group boxes.
Group boxes only make sense in layouts where controls are going to be overlapped - which styles like WS_CLIBSIBLINGS | WS_CLIPCHILDREN only make sense in layouts where there is NO control overlap.
The only way to get overlapping controls to work flicker free would be to actually make the grouped controls children of the group box. Then they'd be clipped out of its area when it paints.
Microsoft added a style to Windows 2000 to fix this issue: WS_EX_COMPOSITED that forces a bottom to top paint order on child controls and paints everything in the context of the parent windows WM_PAINT message - but they promptly broke that style with Windows Vista and 7 - WS_EX_COMPOSITED only works now if aero glass is disabled. Ew.
I have tried several methods, but problems always exist. Sometimes the sub-window didn't refresh and sometimes the sub-window will keep blink.
This is a sample project that i have written
http://rapidshare.com/files/283950611/TestProject.7z.html
My method to implement that is:
Put a scroll bar on the top of sub-window, whenever the scroll bar was dragged, the sub-window would be moved as well.
And every dialog is inherited from CDialogBase, All the drawing is done in this class, Drawer.h is a helper for drawing.
Only when the DC that user assigned is dirty, then system will redraw the window, it is used for accelerating the painting.
WS_EX_LAYERED only can be added to with top level window, not sub-window; I've tried to modify the window style from WS_CHILD to WS_OVERLAPPED, and then using layed window, and then clip the visiable area of the window, but, the result is not what I expected.
Anywhere, thank you for your advice...
Have you considered using WS_EX_LAYERED and then using UpdateLayeredWindow. It can get quite complicated but allows for things like per-pixel alpha and eliminates flicker like you are seeing.
Look here:
http://www.nuonsoft.com/blog/2009/05/27/how-to-use-updatelayeredwindow/
for more info.