General Solution for a Transparent Control

Introduction

In UI development, you have to implement some nice effects, and making some controls to be transparent is a problem that you often meet. In this article, I present an approach to implement the transparency of controls. The source code includes the class CTransparentHelper based on the Win32 API, and it can be used in MFC, ATL, WTL, Win32 applications, or may be some other framework. I will develop a new version because I use it at my work now, so if you have any suggestions, bug reports, or problems, please send it to me. And, you can also visit my technical blog to get more information.

Background

I wrote this code because I needed some transparent controls such as buttons, slider controls, and progress controls. I found that some methods available online are not effective when the parent window moves, or when the control moves; this is a problem when you want to use a transparent control in a resizable dialog. So, I wrote CTransparentHelper; you can have a smooth transparency effect when MoveWindow is called, and the class is suitable for all controls.

Features

  • No framework dependency.
  • Can be used for controls of different types.
  • Can be used for multi-layer transparency.
  • Easy to use in the current code.

Using the Code

Before introducing how to use the source code, I suggest using a memory DC to store the background DC of the parent dialog. This is convenient for the transparency of child controls, and also boosts the efficiency of drawing. For detailed information, please refer to the source code.

Include "TransparentHelper.h"

Include "TransparentHelper.h" in the file of the control that needs to be transparent. And, add an object of type CTransparentHelper.

#pragma once

#include"TransparentHelper.h"
// CSliderCtrlEx

class CSliderCtrlEx : public CSliderCtrl
{
   .........
   CTransparentHelper m_objTrans;
}

Initialize the object of CTransparentHelper

void CSliderCtrlEx::PreSubclassWindow()
{

   // TODO: Add your specialized code here and/or call the base class
   .......

   CSliderCtrl::PreSubclassWindow();
   m_objTrans.Install( GetSafeHwnd());
   ......
}

Call the function TransparentBk of CTransparentHelper when you need.

BOOL CSliderCtrlEx::OnSliderDrawChannel( CDC* pDC,
   CRect& rect, UINT nState)
{
   ......
   if ( m_objTrans.IsValid() )
   {
      m_objTrans.TransparentBk( pDC->GetSafeHdc(), GetSafeHwnd());
   }
   .........
   return TRUE;
}

Add code to the control's parent window

Sometimes, the parent window is a dialog. I need to deal with the message WM_TRANSPARENT_BK, which is sent from the transparent control in order to get back the DC.

LRESULT CTransparentControlDlg::OnTransaprentBk( WPARAM wParam,
                                                 LPARAM lParam)
{
   HDC hdc = ( HDC)wParam;
   HWND hwnd = ( HWND)lParam;

   CTransparentHelper::OnTranparentControl( m_pMemDC->GetSafeHdc(), 
                                          (WPARAM)hdc, (LPARAM)hwnd);
   return TRUE;
}
Remark: The m_pMemDC is the memory DC of the dialog, which will be changed when the dialog's size changes.

Notfiy children when background changes

When the dialog's memory DC changes, it must notify the child which has a transparent tag.

void CTransparentControlDlg::BuildBkDC()
{
   //rebuild the background dc
   ........
   //when the parent dialog's background is rebuilt,
   //notify the child which has an transparent tag.
   CTransparentHelper::NotifyTransparentChild( GetSafeHwnd());
}

The message WM_NOTIFY_TRANSPARENT

The transparent control needs to deal with the WM_NOTIFY_TRANSPARENT message sent by the parent when the background changes.

Remark: For some controls under some drawing methods (for example, NM_CUSTOMDRAW), Invalidate will not cause a real repaint. So, I added the WM_NOTIFY_TRANSAPRENT message to make it compatible. If the transparent control will repaint itself after calling Invalidate, it needn't deal with the message.
LRESULT CSliderCtrlEx::OnNotifyTransparent( WPARAM wParam,
                                            LPARAM lParam)
{
   if ( ::IsWindowEnabled( GetSafeHwnd()))
   {
      ::EnableWindow( GetSafeHwnd(),FALSE);
      ::EnableWindow( GetSafeHwnd(),TRUE);
   }
   else
   {
      ::EnableWindow( GetSafeHwnd(),TRUE);
      ::EnableWindow( GetSafeHwnd(),FALSE);
   }
   //This operation is for the repaint of slider control,
   //because Invalidate can't bring the NM_CUSTOMDRAW message.
   //M..., this may not the best method to solve the problem.
   //If you have another method, please tell me.

   return TRUE;
}


About the Author

alex ding

Software architect and developer with over 8 years of experience, specializing in window development using C++. Welcome to my home page: http://www.uieasy.com.

Downloads

Comments

  • study

    Posted by bingwa on 10/30/2008 12:44am

    good.mark here

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds