News | Articles | Libraries | Developer Tools | Books | Forum Links | Search   
Sections:
 

How to make static controls transparent?

By Alexander Shargin, April 28, 2003.
Print version

Question

I have a dialog with some static controls on it. The dialog displays a bitmap on the background. I want to make my static controls transparent. How can I do it? I tried to handle WM_CTLCOLOR message but this doesn't work. What did I do wrong?

Answer

Correct handler for WM_CTLCOLOR message looks like this:

HBRUSH CTransparentCtlDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if(nCtlColor == CTLCOLOR_STATIC) { hbr = (HBRUSH)::GetStockObject(HOLLOW_BRUSH); pDC->SetBkMode(TRANSPARENT); } return hbr; }

This code works well on desktop Windows but fails on CE. Well actually the static becomes transparent. The problem is that the dialog never draws anything under child controls (neither from OnEraseBkgnd nor from OnPaint) - even if WS_CLIPCHILDREN style is not set! Here is a quote from CreateWindow API doc which describes this behaviour: "All windows implicitly have the WS_CLIPSIBLINGS and WS_CLIPCHILDREN styles."

So you will have to use a different approach. The easiest way to create transparent labels is to draw them manually from WM_ERASEBKGND or WM_PAINT handler of your dialog. You can use DrawText to do this. In order to make the text transparent you have to call CDC::SetBkMode and set background mode to TRANSPARENT before you draw your labels. Here is a simple OnPaint handler which draws a transparent label on the dialog.

void CTransparentCtlDlg::OnPaint() { CPaintDC dc(this); // device context for painting dc.SetBkMode(TRANSPARENT); dc.DrawText ( _T("Label text goes here..."), -1, CRect(5, 5, 235, 25), DT_SINGLELINE|DT_CENTER|DT_VCENTER ); }

This approach works well but there are some problems with it. First, you can not use resource editor to position your labels on the dialog. Second, localization of your app becomes more difficult since instead of localizing a dialog resource you have to localize string resources for all labels and manually check if new labels fit in the dialog layout.

To fix these problems you can do the following. Place static controls in your dialog like you already do but make them invisible (remove Visible flag in the control's properties). Then in OnPaint handler iterate through all static controls, obtain their text and position and draw them as in the previous sample. You can also analyze static's style and specify corresponding DrawText flags to make this approach even more generic. Here is the code which does all this for you.

void CTransparentCtlDlg::OnPaint() { CPaintDC dc(this); // device context for painting dc.SetBkMode(TRANSPARENT); CWnd *pWnd = GetWindow(GW_CHILD); while(pWnd != NULL) { TCHAR szClassName[255]; ::GetClassName(pWnd->GetSafeHwnd(), szClassName, 255); if(_tcscmp(szClassName, _T("static")) == 0) { CString strText; pWnd->GetWindowText(strText); CRect rc; pWnd->GetWindowRect(&rc); ScreenToClient(&rc); DWORD dwStyle = pWnd->GetStyle(); int nDTFlags = 0; if((dwStyle & SS_NOPREFIX) != 0) { nDTFlags |= DT_NOPREFIX; } if((dwStyle & SS_CENTER) != 0) { nDTFlags |= DT_CENTER; } else if((dwStyle & SS_RIGHT) != 0) { nDTFlags |= DT_RIGHT; } else { nDTFlags |= DT_LEFT; } if((dwStyle & SS_LEFTNOWORDWRAP) != 0) { nDTFlags |= DT_SINGLELINE; } else { nDTFlags |= DT_WORDBREAK; } dc.DrawText(strText, -1, &rc, nDTFlags); } pWnd = pWnd->GetNextWindow(); } }

You can download a sample project - TransparentCtl.zip (17 Kb).

Related resources:

Discuss

Discuss this article. Here you can write your comments and read comments of other developers.
Rate this article:     Poor Excellent    
 12345 
© 2001-2005 Pocket PC Developer Network, a division of Spb Software House