Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / MFC

Perfect Semi-transparent & Shaped Dialogs with Standard, ActiveX, and Translucent Controls for Windows 2000+

Rate me:
Please Sign up or sign in to vote.
4.93/5 (119 votes)
9 Feb 2010CPOL5 min read 3.2M   23.5K   226   96
This article tries to find a way to show standard controls, ActiveX controls, translucent controls on layered windows. Native MFC source code provided.

Introduction 

First, let me show you some screenshots captured from the demo program. The program demonstrates semi-transparent dialogs with standard, ActiveX (like WebBrowser Control, Flash Control) and translucent controls which are compatible with Windows 2000 and higher.  

Translucent Dialog with Standard Control

Translucent Dialog with WebPage

Translucent Dialog with WebPage

Background

Jerry.Wang has given a way in his article: Cool, Semi-transparent and Shaped Dialogs with Standard Controls for Windows 2000 and Above. In short, he creates two dialogs: one (the real dialog) is in charge of processing user input events and Windows messages, the other (the fake dialog) is in charge of the presentation. The fake one is created by CreateWindowEx with the styles WS_EX_LAYERED, WS_EX_TRANSPARENT, and WS_EX_NOACTIVATE, and always kept the same size / position as the real one. The real one is almost transparent because its alpha value is modified to 5 by SetLayeredWindowAttributes.

In his article, when the presentation needs to be refreshed, the background image is painted first. All the standard child controls will be captured by sending the WM_PRINT message, and painted at the same position on the fake window. Especially, for EDIT controls, EditBox / Editable ComboBox / etc., we need to draw the caret by ourselves.

But, there are some problems:

  • The dialog is NOT a real shaped one, i.e. the hit testing is NOT based on the shape and transparency of the dialog. This means that the areas of the dialog that are color-keyed or whose alpha value is zero will NOT let the mouse messages through.
  • NOT All standard controls are supported. Some of the controls such as slider, cannot work with WM_PRINT; in that case, the controls won't display correctly.
  • The ActiveX control is NOT supported. The ActiveX control like the WebBrowser control and Flash control is used to support a wide variety of OLE functionality and can be customized to fit many software needs. It cannot work with WM_PRINT too.
  • The dialog works in a way that if there is one pixel that needs to be updated, the whole window will be refreshed. Therefore, if the dialog is very large and complex, or has a lot of child controls, it may cause performance issues.

I'm going to propose another approach which can solve the above problems. The following picture shows the mechanism:

Showing the mechanism of translucent dialog

The translucent dialog is created with the styles WS_EX_LAYERED, and WS_OVERLAPPED. When it is being created, a standard dialog is created by CreateWindowEx with the styles WS_EX_LAYERED, WS_POPUP, NO WS_BORDER, NO WS_SIZEBOX, and NO WS_DLGFRAME.

The translucent dialog is in charge of processing the translucent background and the translucent controls; the standard dialog is in charge of processing the standard controls and ActiveX controls. The standard dialog is always kept the same size / position as the translucent one.

A translucent control which supports the per-pixel alpha value must be derived from the class CTranslucentWnd. You can override the method Render to draw it. In the source code, I has provided two translucent controls: CTranslucentButton and CTranslucentProgressBar. The CTranslucentButton is used to replace the CBitmapButton, and CTranslucentProgressBar is used to replace the CProgressCtrl.

For the standard controls and Active controls, you must put them on the standard dialog. Because the standard dialog covers the translucent dialog, the translucent controls cannot process the user input. How to solve it? The solution is making the standard dialog fully transparent. The API SetLayeredWindowAttributes with the zero alpha value can help you. But all the controls on it are also fully transparent.

But how to make the standard dialog fully transparent while the controls on it are opaque? This can be done by calling SetLayeredWindowAttributes with the color-key. In the OnInitDialog of the standard dialog, the API SetLayeredWindowAttributes is called with a certain color. In the processing of the message WM_CTLCOLOR with nCtlColor == CTLCOLOR_DLG, if it returns the solid brush that has the specified color, the standard dialog is fully transparent while the controls on it are also opaque.

You can get more details by looking into the source code.

Using the Code in Native C++ / MFC

Step 1

Copy all the files in /Core/*.* to your project.

Step 2

You need an image file to be the dialog background. You'd better choose PNG or TIFF which support the alpha channel. The image file can be embedded into a resource or placed on disk, judged by yourself.

Step 3

Design your standard dialog in the Resource View. In the Properties window, set the following properties:

Border: None
Overlapped Window: False
Style: Popup 

You'd better choose a certain color (i.e. transparent color) as the color-key, and drag some standard controls or ActiveX controls to it. Replace the dialog base class from CDialog to CStandardDialog.

C++
// Here, the transparent color is green.

CDemoStandardDlg::CDemoStandardDlg(CWnd* pParent /*=NULL*/)
    : CStandardDialog(CDemoStandardDlg::IDD, RGB(0, 255, 0), pParent)
{

}

Step 4

Design your translucent dialog in the Resource View. In the Properties window, set the following properties:

Overlapped Window: False
Style: Overlapped 

Replace the dialog base class from CDialog to CTranslucentDialog.

C++
// Load from disk file

CDemoTranslucentDlg::CDemoTranslucentDlg(LPCTSTR lpszFile, CWnd* pParent /*=NULL*/)
	: CTranslucentDialog(CDemoTranslucentDlg::IDD, lpszFile, pParent)
{
}

// Load from resource 
CDemoTranslucentDlg::CDemoTranslucentDlg(UINT nImgID, LPCTSTR lpszType
	/*=_T("PNG")*/, HINSTANCE hResourceModule/*=NULL*/, CWnd* pParent /*=NULL*/)
	: CTranslucentDialog(CDemoTranslucentDlg::IDD, nImgID, 
	lpszType, hResourceModule, pParent)
{
}

Step 5 (optional)

If you need some translucent controls, drag some controls (like button, checkbox, progress bar) to the translucent dialog. Subclasses your translucent controls to the corresponding CTranslucentWnd class, like subclass CButton to CTranslucentButton. The following demo source is from the demo program:

C++
// In the CDemoTranslucentDlg.h
    CTranslucentButton m_btnTest;
    CTranslucentProgressBar m_ctrlProgress;

// In the CDemoTranslucentDlg.cpp
void CDemoTranslucentDlg::DoDataExchange(CDataExchange* pDX)
{
    CTranslucentDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON1, m_btnTest);
    DDX_Control(pDX, IDC_PROGRESS, m_ctrlProgress);
}

Step 6

Override the method CreateStandardDialog and OnInitChildrenWnds of your translucent dialog class. The method CreateStandardDialog is in charge of creating the corresponding standard dialog, and the method OnInitChildrenWnds is in charge of setting the translucent controls' properties and registering them to the translucent dialog. The following demo source is from the demo program:

C++
// In the CDemoTranslucentDlg.cpp
CStandardDialog* CDemoTranslucentDlg::CreateStandardDialog()
{
	return ::new CDemoStandardDlg(this);
}

void CDemoTranslucentDlg::OnInitChildrenWnds()
{
	LPCTSTR szImageList[TWS_BUTTON_NUM] = { _T("res\\close_normal.PNG"), 
		_T("res\\close_disable.png"), _T("res\\close_over.PNG"), 
		_T("res\\close_down.PNG"), 0};
	m_btnTest.LoadImageList(szImageList);
	RegisterTranslucentWnd(&m_btnTest);

	m_ctrlProgress.MoveWindow(400, 400, 146, 61, TRUE);
	m_ctrlProgress.SetPos(50);
	m_ctrlProgress.SetFgImage(_T("res\\progress.png"));
	RegisterTranslucentWnd(&m_ctrlProgress);
}

Something Important

The article is based on the Jerry.Wang's article, and uses his CUtility class to load image. Thank you very much, Jerry.Wang.

The source code uses the GdiPlus to draw the translucent controls, so you must setup the Gdiplus environment before using my code.

The source code only provides two kinds of translucent controls. You can extend the CTranslucentWnd to support some other controls. But in my own projects, they are enough. If you can provide some other translucent controls, please share them with me.

If some controls on the standard dialog have some pixels whose colors are the same as the transparent color of the dialog, the pixels are also fully transparent. You can make use of the feature to create some effects, like making some controls become irregular.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
China China
D.K.Wang is working for a leading interactive entertainment media company located in Shanghai, China. Skilled in Windows C++, MFC, WTL, PHP etc. Started with professional games development since 2005, now devoted to the core functionality such as graphics rendering, physics simulation and scene management for a household game engine.

Comments and Discussions

 
QuestionA problem that bothers me Pin
zhaoze8726-Jul-10 17:22
zhaoze8726-Jul-10 17:22 
AnswerRe: A problem that bothers me Pin
D.K.Wang3-Aug-10 4:16
D.K.Wang3-Aug-10 4:16 
GeneralSmall bug Pin
Enrico Detoma18-Jul-10 23:08
Enrico Detoma18-Jul-10 23:08 
GeneralRe: Small bug Pin
D.K.Wang19-Jul-10 3:24
D.K.Wang19-Jul-10 3:24 
GeneralBitmap Leak in CTranslucentDialog::UpdateView() Pin
DynamicAdventures11-Feb-10 7:56
DynamicAdventures11-Feb-10 7:56 
GeneralRe: Bitmap Leak in CTranslucentDialog::UpdateView() Pin
D.K.Wang17-Feb-10 3:16
D.K.Wang17-Feb-10 3:16 
QuestionWhat is now in the upgrade Pin
Tage Lejon9-Feb-10 23:04
Tage Lejon9-Feb-10 23:04 
AnswerRe: What is now in the upgrade Pin
D.K.Wang11-Feb-10 4:19
D.K.Wang11-Feb-10 4:19 
Last changed:

1. fixed the bug: Heap corruption loading images from resource id
2. fixed the bug: Response slowly, i.e. the state image changed slowly when the mouse enter or leave the button
GeneralHeap corruption loading images from resource id Pin
MGDBP1-Feb-10 0:49
MGDBP1-Feb-10 0:49 
GeneralRe: Heap corruption loading images from resource id Pin
D.K.Wang3-Feb-10 4:11
D.K.Wang3-Feb-10 4:11 
GeneralRe: Heap corruption loading images from resource id Pin
D.K.Wang6-Feb-10 17:31
D.K.Wang6-Feb-10 17:31 
GeneralRe: Heap corruption loading images from resource id Pin
MGDBP7-Feb-10 1:00
MGDBP7-Feb-10 1:00 
Questionuse this code in winforms. net 2008 c # Pin
agvr30-Dec-09 3:37
agvr30-Dec-09 3:37 
AnswerRe: use this code in winforms. net 2008 c # Pin
D.K.Wang3-Feb-10 4:05
D.K.Wang3-Feb-10 4:05 
GeneralVery helpful! Pin
stjn118-Dec-09 2:59
stjn118-Dec-09 2:59 
GeneralRe: Very helpful! Pin
D.K.Wang21-Dec-09 2:07
D.K.Wang21-Dec-09 2:07 
QuestionWhy Translucent Button's Text became transparent ? Pin
jjksam8-Dec-09 21:55
jjksam8-Dec-09 21:55 
AnswerRe: Why Translucent Button's Text became transparent ? Pin
jjksam8-Dec-09 23:13
jjksam8-Dec-09 23:13 
GeneralGreat Article Pin
envmapping24-Oct-09 4:31
envmapping24-Oct-09 4:31 
Generalgood job Pin
iebrowser24-Oct-09 4:04
iebrowser24-Oct-09 4:04 
GeneralMy vote of 1 Pin
MaheshV0221-Oct-09 0:58
MaheshV0221-Oct-09 0:58 
GeneralRe: My vote of 1 Pin
D.K.Wang21-Oct-09 4:34
D.K.Wang21-Oct-09 4:34 
GeneralRe: My vote of 1 Pin
Octopod16-Feb-10 5:45
Octopod16-Feb-10 5:45 
GeneralRe: My vote of 1 Pin
Paul Belikian4-Jan-11 8:16
Paul Belikian4-Jan-11 8:16 
Generalgreat article Pin
afxfish2-Oct-09 21:31
afxfish2-Oct-09 21:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.