Producing translucent dialog boxes and windows without flickering






4.94/5 (11 votes)
Aug 7, 2002

135630

3109
Enhancing window fade-in to render common controls correctly and to allow the window to remain transparent after the fade-in
Problem
TheAnimateWindow()
API with the AW_BLEND
parameter
is supposed to fade in and out windows smoothly. Basically, it has two drawbacks:
- Text and ListView controls (and several others) aren't rendered correctly during fade-in.
- You cannot specify a translucency for the window, i.e., after the animation is over, the window is opaque.
Workaround?
There seemed to be a simple workaround for this: Adding theWS_EX_LAYERED
extended style to the window and calling
SetLayeredWindowAttributes()
with the desired alpha value, as
described in the MSDN Library and in various other sources.
Unfortunately, this didn't work either, at least on my XP Pro system. The code
produced a very nasty flickering: the window area was
initially black.
Solution
The following code shows how to fade in a dialog to a predefinded translucency without flickering:INT_PTR CALLBACK DialogProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { RECT rcDesktop; RECT rcMe; BYTE bTranslucency; const DWORD ANIMATION_MILLIS = 200; const BYTE TRANSLUCENCY = 192; const BYTE TRANSLUCENCY_STEP = 16; const DWORD TRANSLUCENCY_TIMEOUT = TRANSLUCENCY_STEP * ANIMATION_MILLIS / TRANSLUCENCY; switch (uMsg) { case WM_INITDIALOG: // Make it a layered window. ::SetWindowLong(hwndDlg, GWL_EXSTYLE, ::GetWindowLong(hwndDlg, GWL_EXSTYLE) | WS_EX_LAYERED); // Completely transparent window - note the third parameter ::SetLayeredWindowAttributes(hwndDlg, 0, 0, LWA_ALPHA); // Show it _first_ ::ShowWindow(hwndDlg, SW_SHOW); // Redraw contents NOW - no flickering since the window's not visible ::RedrawWindow(hwndDlg, NULL, NULL, RDW_UPDATENOW); // Normally, you would use a timer here... for (bTranslucency = 0; bTranslucency < TRANSLUCENCY; bTranslucency+=TRANSLUCENCY_STEP) { // Adjust the translucency ::SetLayeredWindowAttributes(hwndDlg, 0, bTranslucency, LWA_ALPHA); // Wait ::Sleep(TRANSLUCENCY_TIMEOUT); } // Set the final translucency ::SetLayeredWindowAttributes(hwndDlg, 0, bTranslucency, LWA_ALPHA); break; } return 0; }Note that the call to
ShowWindow()
is usually done by the
CreateDialogXXX()
functions if the dialog template has the
WS_VISIBLE
style set. For our purposes, we have to do it right
here in response to the WM_INITDIALOG
message.