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

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

0.00/5 (No votes)
9 Feb 2010 6  
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.

// 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.

// 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:

// 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:

// 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 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