Click here to Skip to main content
11,578,707 members (60,821 online)
Click here to Skip to main content

Transparent ListBox

, 19 Aug 2005 CPOL 208.4K 6.2K 80
Rate this:
Please Sign up or sign in to vote.
How to accomplish true transparency in listboxes.

Introduction

Any experienced Windows programmer can tell you that transparency is not a trivial task in Windows. A transparent ListBox control is no exception. Actually ListBoxes are a bit harder than other controls. And the reason is the way ListBoxes do their scrolling. But overall it is a pretty simple concept to implement.

For example, in order to make a static control transparent, all anyone will have to do is to handle the WM_ERASEBKGND, and to also repaint the control when the user calls SetWindowText.

In the case of a ListBox, let’s say that we take over the WM_ERASEBKGND message and return TRUE (basically the easiest way to achieve transparency). When the user presses the down button of the Listbox’s scrollbar, what Windows does is bitblt the item's top index + 1 to the last shown item one line up, and then simply draws the new item. What happens there is that the background gets copied up with the item. Clearly not the results we would be looking for.

How to do it

So how would we achieve transparency with a ListBox? Let’s start with an owner draw ListBox.

First thing we have to do is copy the parent window's image before the first time the ListBox is drawn, this will give us the background for the listbox. We can do this in the WM_ERASEBKGND message handler. The first time this message is received the ListBox has not yet been drawn, so it is a safe place to take a snapshot of the parent window.

BOOL CTransparentListBox::OnEraseBkgnd(CDC* pDC) 
{
   if (!m_HasBackGround)
   {
       CWnd *pParent = GetParent();
       if (pParent)
       {
         CRect Rect;
         GetClientRect(&Rect);
         ClientToScreen(&Rect);
         pParent->ScreenToClient(&Rect);
         CDC *pDC = pParent->GetDC();
         m_Width = Rect.Width();
         m_Height = Rect.Height();
         CDC memdc;
         memdc.CreateCompatibleDC(pDC);
         CBitmap *oldbmp = memdc.SelectObject(&m_Bmp);
         memdc.BitBlt(0,0,Rect.Width(),Rect.Height(), 
                     pDC,Rect.left,Rect.top,SRCCOPY);
         memdc.SelectObject(oldbmp);
         m_HasBackGround = TRUE;
         pParent->ReleaseDC(pDC);
       }
   }
   return TRUE;
}

The second thing that we have to handle is drawing each item on the screen. Because of the scrolling we can’t trust the ListBox to do any of our drawing for us. So we override the DrawItem method and do nothing. And in turn place the code that would normally be placed there in a separate DrawItem method which we can call when we want to paint the ListBox, which we will in the OnPaint method. What OnPaint does is simply draw the background snapshot on to a memory DC, draw the visible items on to the same memory DC, and then bitblt the entire thing on the ListBox DC. Simple so far.

void CTransparentListBox::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
    //do nothing when the listbox asks you to draw an item
}

void CTransparentListBox::DrawItem(CDC &Dc, 
            int Index,CRect &Rect,BOOL Selected)
{
   if (Index == LB_ERR || Index >= GetCount())
       return;

   if (Rect.top < 0 || Rect.bottom > m_Height)
   {
       return;
   }
   CRect TheRect = Rect;
   Dc.SetBkMode(TRANSPARENT);

   CDC memdc;
   memdc.CreateCompatibleDC(&Dc);

   CFont *pFont = GetFont();
   CFont *oldFont = Dc.SelectObject(pFont);
   CBitmap *oldbmp = memdc.SelectObject(&m_Bmp);
   Dc.BitBlt(TheRect.left,TheRect.top,TheRect.Width(), 
             TheRect.Height(),&memdc,TheRect.left,
             TheRect.top,SRCCOPY);
   CString Text;
   GetText(Index,Text);
   if (m_Shadow)
   {
       if (IsWindowEnabled())
       {
           Dc.SetTextColor(m_ShadowColor);
       }
       else
       {
           Dc.SetTextColor(RGB(255,255,255));
       }
       TheRect.OffsetRect(m_ShadowOffset,m_ShadowOffset);
       Dc.DrawText(Text,TheRect,DT_LEFT|DT_EXPANDTABS|DT_NOPREFIX);
       TheRect.OffsetRect(-m_ShadowOffset,-m_ShadowOffset);
   }

   if (IsWindowEnabled())
   {
       if (Selected)
       {
           Dc.SetTextColor(m_SelColor);
       }
       else
       {
           Dc.SetTextColor(m_Color);
       }
   }
   else
   {
       Dc.SetTextColor(RGB(140,140,140));
   }
   Dc.DrawText(Text,TheRect,DT_LEFT|DT_EXPANDTABS|DT_NOPREFIX);
   Dc.SelectObject(oldFont);
   memdc.SelectObject(oldbmp);
}

void CTransparentListBox::OnPaint() 
{
   CPaintDC dc(this); // device context for painting

   CRect Rect;
   GetClientRect(&Rect);

   int Width = Rect.Width();
   int Height = Rect.Height();

   //create memory DC's
   CDC MemDC;
   MemDC.CreateCompatibleDC(&dc);
   CBitmap MemBmp;
   MemBmp.CreateCompatibleBitmap(&dc,Width,Height);

   CBitmap *pOldMemBmp = MemDC.SelectObject(&MemBmp);

   //paint the background bitmap on the memory dc
   CBitmap *pOldbmp = dc.SelectObject(&m_Bmp);
   MemDC.BitBlt(0,0,Width,Height,&dc,0,0,SRCCOPY);
   dc.SelectObject(pOldbmp);


   Rect.top = 0;
   Rect.left = 0;
   Rect.bottom = Rect.top + GetItemHeight(0);
   Rect.right = Width;
   
   int size = GetCount();
   //draw each item on memory DC
   for (int i = GetTopIndex(); i < size 
            && Rect.top <= Height;++i)
   {
       DrawItem(MemDC,i,Rect,GetSel(i));
       Rect.OffsetRect(0,GetItemHeight(i));
   }

   //draw the results onto the listbox dc
   dc.BitBlt(0,0,Width,Height,&MemDC,0,0,SRCCOPY);

   MemDC.SelectObject(pOldMemBmp);
}

Third and the tricky part is handling the scroll messages. To overcome the scroll problem, we intercept the WM_VSCROLL message and wrap the call to CListBox::OnVScroll with SetRedraw(FALSE), and SetRedraw(TRUE), followed by a call to RedrawWindow to refresh the content of the listbox. This will give a smooth and flicker free scrolling. Simple!

void CTransparentListBox::OnVScroll(UINT nSBCode, 
                    UINT nPos, CScrollBar* pScrollBar) 
{
   SetRedraw(FALSE);  //prevent any drawing
   CListBox::OnVScroll(nSBCode,nPos,pScrollBar);
   SetRedraw(TRUE);   //restore drawing

   //draw the frame and window content in one shot
   RedrawWindow(0,0,RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
}

The same type of approach has to happen when an item is selected. So we intercept the LBN_SELCHANGE message and force a redraw, since our DrawItem method does nothing.

BOOL CTransparentListBox::OnLbnSelchange()
{
   Invalidate();
   UpdateWindow();
   return TRUE;
}

Using the code

To use this class, simply insert a ListBox into your dialog box. Make sure you have set the Owner-draw and Has Strings flags. Attach a variable of type CTransparentListBox to the control and you are ready to go. My CTransparentListBox class also gives you the ability to specify different fonts, colors, and shadows. This will come in handy on backgrounds that are too busy or too dark for the standard colors, and font size.

class CTestDialog : public CDialog
{
   ....
   CTransparentListBox m_ListBox;
};

void CTestDialog::DoDataExchange(CDataExchange* pDX)
{
   CDialog::DoDataExchange(pDX);
   DDX_Control(pDX, IDC_LIST1, m_ListBox);
}

BOOL CTransStaticDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   m_ListBox.SetFont(12,"Aria", 
          RGB(255,255,255),RGB(255,0,0)); //Optional   

   m_ListBox.AddString(“Test”);
}

Have fun Smile | :)

License

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

Share

About the Author

Ali Rafiee
Architect
United States United States
Ali Rafiee has been developing windows applications using C++ since 1991, and he hasn't looked back since. Ali has been a software development consultant for must of his career, but he has finally settled down and has been working for an educational software company since 2000. While he is not working, he is either learning C#, flying airplanes, playing with his daughter, or answering peoples question on newsgroups, he finds that to be a great learning tool for himself.

Ali is also a Microsoft Visual C++ MVP.

You may also be interested in...

Comments and Discussions

 
QuestionCan I use it on a combobox dropdown list as well? Pin
cpw999cn6-Feb-11 16:36
membercpw999cn6-Feb-11 16:36 
Can I use it on a combobox dropdown list as well?
GeneralThe control doesn't apply to mouse wheel roll Pin
zhang xiaoxuan13-Sep-09 17:50
memberzhang xiaoxuan13-Sep-09 17:50 
AnswerRe: The control doesn't apply to mouse wheel roll Pin
Ali Rafiee13-Sep-09 18:15
memberAli Rafiee13-Sep-09 18:15 
QuestionThis method can not work normally in dynamic created listbox? Pin
e_ilite11-Feb-09 18:10
membere_ilite11-Feb-09 18:10 
GeneralC# Version Pin
Sukhjinder_K24-Jul-07 0:46
memberSukhjinder_K24-Jul-07 0:46 
GeneralTransparent Control Pin
arijit_datta268-Mar-07 20:42
memberarijit_datta268-Mar-07 20:42 
GeneralRe: Transparent Control Pin
Ali Rafiee9-Mar-07 5:48
memberAli Rafiee9-Mar-07 5:48 
GeneralRe: Transparent Control [modified] Pin
arijit_datta2610-Mar-07 2:07
memberarijit_datta2610-Mar-07 2:07 
Questionport to C# ? Pin
Brian Perrin16-Feb-07 9:54
memberBrian Perrin16-Feb-07 9:54 
Generalperfect hscroll [modified] Pin
ram krishna pattnayak20-Nov-06 19:49
memberram krishna pattnayak20-Nov-06 19:49 
GeneralThanks,Till Some problem In ListBox Application Pin
ram krishna pattnayak19-Nov-06 23:37
memberram krishna pattnayak19-Nov-06 23:37 
GeneralRe: Thanks,Till Some problem In ListBox Application [modified] Pin
Ali Rafiee20-Nov-06 10:33
memberAli Rafiee20-Nov-06 10:33 
GeneralHscrollBar in transparent ListBox Pin
ram krishna pattnayak17-Nov-06 19:54
memberram krishna pattnayak17-Nov-06 19:54 
AnswerRe: HscrollBar in transparent ListBox [modified] Pin
Ali Rafiee18-Nov-06 19:56
memberAli Rafiee18-Nov-06 19:56 
Questionhorizontal scroll dont display total text Pin
ram krishna pattnayak17-Nov-06 0:59
memberram krishna pattnayak17-Nov-06 0:59 
QuestionRe: horizontal scroll dont display total text Pin
Ali Rafiee17-Nov-06 17:31
memberAli Rafiee17-Nov-06 17:31 
Generalhorizontal scroll Pin
_kane_16-Nov-06 1:16
member_kane_16-Nov-06 1:16 
AnswerRe: horizontal scroll [modified] Pin
Ali Rafiee16-Nov-06 5:24
memberAli Rafiee16-Nov-06 5:24 
GeneralAssept Pin
denim666621-Aug-06 19:30
memberdenim666621-Aug-06 19:30 
GeneralRe: Assept Pin
Ali Rafiee22-Aug-06 7:42
memberAli Rafiee22-Aug-06 7:42 
GeneralRe: Assept Pin
denim666623-Aug-06 0:16
memberdenim666623-Aug-06 0:16 
AnswerRe: Assert - Fixed Pin
Ali Rafiee23-Aug-06 4:37
memberAli Rafiee23-Aug-06 4:37 
GeneralRe: Assert - Fixed Pin
denim666623-Aug-06 19:46
memberdenim666623-Aug-06 19:46 
Generalporting to ce Pin
Fernando A. Gómez F.30-Jun-06 8:39
memberFernando A. Gómez F.30-Jun-06 8:39 
GeneralEnable and disable items in Listbox Pin
Rosh29-Jun-06 20:33
memberRosh29-Jun-06 20:33 
GeneralRe: Enable and disable items in Listbox Pin
Ali Rafiee17-Nov-06 17:40
memberAli Rafiee17-Nov-06 17:40 
Generalfailed to empty list box when calling ResetConten() in code Pin
MerlinYen11-Jan-06 14:56
memberMerlinYen11-Jan-06 14:56 
GeneralRe: failed to empty list box when calling ResetConten() in code Pin
MerlinYen11-Jan-06 15:03
memberMerlinYen11-Jan-06 15:03 
AnswerFix : failed to empty list box when calling ResetConten() in code Pin
Ali Rafiee12-Jan-06 7:49
memberAli Rafiee12-Jan-06 7:49 
GeneralRe: Fix : failed to empty list box when calling ResetConten() in code Pin
MerlinYen17-Jan-06 22:09
memberMerlinYen17-Jan-06 22:09 
QuestionCapturing right click button on listbox items Pin
imadulhaq22-Dec-05 19:52
memberimadulhaq22-Dec-05 19:52 
AnswerRe: Capturing right click button on listbox items Pin
Ali Rafiee23-Dec-05 5:44
memberAli Rafiee23-Dec-05 5:44 
QuestionAbout listview Pin
imadulhaq21-Dec-05 20:44
memberimadulhaq21-Dec-05 20:44 
QuestionRegarding updating listbox Pin
imadulhaq21-Dec-05 19:19
memberimadulhaq21-Dec-05 19:19 
GeneralA big problem Pin
imadulhaq21-Dec-05 19:17
memberimadulhaq21-Dec-05 19:17 
GeneralRe: A big problem Pin
Ali Rafiee22-Dec-05 5:48
memberAli Rafiee22-Dec-05 5:48 
GeneralRe: A big problem Pin
imadulhaq22-Dec-05 19:52
memberimadulhaq22-Dec-05 19:52 
GeneralBugfix Pin
Isajanyen25-Oct-05 1:53
sussIsajanyen25-Oct-05 1:53 
GeneralRe: Bugfix Pin
Isajanyan25-Oct-05 2:03
sussIsajanyan25-Oct-05 2:03 
GeneralRe: Bugfix Pin
little_frog23-Mar-10 0:42
memberlittle_frog23-Mar-10 0:42 
GeneralRe: Bugfix Pin
Ali Rafiee24-Mar-10 4:26
memberAli Rafiee24-Mar-10 4:26 
GeneralRe: Bugfix Pin
little_frog24-Mar-10 23:32
memberlittle_frog24-Mar-10 23:32 
GeneralRe: Bugfix Pin
Ali Rafiee25-Mar-10 5:33
memberAli Rafiee25-Mar-10 5:33 
GeneralRe: Bugfix Pin
little_frog25-Mar-10 6:22
memberlittle_frog25-Mar-10 6:22 
GeneralRe: Bugfix Pin
Ali Rafiee25-Mar-10 6:32
memberAli Rafiee25-Mar-10 6:32 
GeneralRe: Bugfix Pin
little_frog25-Mar-10 6:41
memberlittle_frog25-Mar-10 6:41 
GeneralRe: Bugfix Pin
Ali Rafiee26-Mar-10 5:07
memberAli Rafiee26-Mar-10 5:07 
GeneralRe: Bugfix Pin
little_frog31-Mar-10 15:41
memberlittle_frog31-Mar-10 15:41 
GeneralRemove the Scroll Bar Pin
khaled_The_Prog29-Sep-05 15:07
memberkhaled_The_Prog29-Sep-05 15:07 
GeneralRe: Remove the Scroll Bar Pin
AliRafiee29-Sep-05 18:32
memberAliRafiee29-Sep-05 18:32 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150603.1 | Last Updated 19 Aug 2005
Article Copyright 2005 by Ali Rafiee
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid