Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Producing translucent dialog boxes and windows without flickering

0.00/5 (No votes)
6 Aug 2002 1  
Enhancing window fade-in to render common controls correctly and to allow the window to remain transparent after the fade-in

Problem

The AnimateWindow() API with the AW_BLEND parameter is supposed to fade in and out windows smoothly. Basically, it has two drawbacks:
  1. Text and ListView controls (and several others) aren't rendered correctly during fade-in.
  2. You cannot specify a translucency for the window, i.e., after the animation is over, the window is opaque.
Clicking 'No' in the sample project demonstrates both problems.

Workaround?

There seemed to be a simple workaround for this: Adding the WS_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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here