Click here to Skip to main content
Click here to Skip to main content

CRadioListBox: A ListBox with Radio Buttons (MFC version)

, 22 Dec 2007
Rate this:
Please Sign up or sign in to vote.
How to implement an owner-drawn ListBox with radio buttons instead of standard selection highlight

Introduction

Recently I had discussed in a Visual C++ forum about a member's request to implement a custom ListBox control similar to CCheckListBox, but with radio buttons. Initially it appeared to be trivial, since the ListBox control's unique selection version complies with asker requirements, but I have concluded that this control has some advantages:

  • It is clearer, with radio buttons, that options are mutually exclusive.
  • Is a good alternative to a group of radio buttons, because you have to maintain just one control.
  • It inherits some useful features like scrolling, sort and multi-column.
  • It will be easier to change options dynamically, as shown in the demo application.
  • It will be easier to manage selection events, also shown in the demo application.

Using the Code

To implement CRadioListBox into your project, you just need to do a few steps:

  • Include RadioListBox.cpp and RadioListBox.h in your project.
  • Insert a CRadioListBox object into your dialog class declaration (*.h file).
  • Put a standard ListBox control into your dialog's template layout, ensuring that the "owner draw fixed" property is active.
  • Create or modify an OnInitDialog event and subclass a corresponding ListBox.

For example, if your dialog is named CMyDialog, the ListBox member is m_RadioListBox and the control ID is IDC_RADIOLISTBOX, then you can subclass the control in the following way:

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

    // Some other custom source code here

    m_RadioListBox.SubclassDlgItem(IDC_RADIOLISTBOX, this);   
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

There are other ways to subclass a control in a MFC application, as explained by Eric Sanchez in his article "Control Subclassing," but I think the above version is the shortest one.

Transparency

As you can see in the above pictures, there is a transparency feature, so the ListBox can imitate radio button's aspect. This can be easily done by setting the WS_EX_TRANSPARENCY attribute of the control in the Visual C++ Dialog Editor. Also, it will be necessary to turn WS_BORDER's style "off."

CRadioListBox Internals

The CRadioListBox class is derived from the CListBox class with just one derived method: DrawItem. The method does not highlight the selected item as in a standard ListBox control, but draws a radio button instead. It also manages the focus state to draw the focus rectangle properly and the background color according to the transparency attribute. I know it could have been better, but this first version runs OK under different screen conditions. Here is the source code:

void CRadioListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    // just draws focus rectangle when listbox is empty
    if (lpDrawItemStruct->itemID == (UINT)-1)
      {
         if (lpDrawItemStruct->itemAction & ODA_FOCUS)
         pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
         return;
      }
    else
      {
         int selChange = lpDrawItemStruct->itemAction & ODA_SELECT;
         int focusChange = lpDrawItemStruct->itemAction & ODA_FOCUS;
         int drawEntire = lpDrawItemStruct->itemAction & ODA_DRAWENTIRE;
         if (selChange || drawEntire) 
         {
               BOOL sel = lpDrawItemStruct->itemState & ODS_SELECTED;
               // Draws background rectangle, color depends on transparency
               pDC->FillSolidRect(&lpDrawItemStruct->rcItem, 
               ::GetSysColor((GetExStyle()&WS_EX_TRANSPARENT)?
                                                COLOR_BTNFACE:COLOR_WINDOW));
               // Draw radio button
               int h = 
                 lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;
               CRect rect(lpDrawItemStruct->rcItem.left+2, 
                          lpDrawItemStruct->rcItem.top+2, 
                          lpDrawItemStruct->rcItem.left+h-3, 
                          lpDrawItemStruct->rcItem.top+h-3);
               pDC->DrawFrameControl(&rect, DFC_BUTTON, 
                       DFCS_BUTTONRADIO | (sel?DFCS_CHECKED:0));
               // Draws item text
               pDC->SetTextColor(COLOR_WINDOWTEXT);
               pDC->SetBkMode(TRANSPARENT);
               lpDrawItemStruct->rcItem.left += h;
               pDC->DrawText((LPCTSTR)lpDrawItemStruct->itemData, 
                            &lpDrawItemStruct->rcItem, DT_LEFT);
         }
         // draws focus rectangle
         if (focusChange || (drawEntire && 
                  (lpDrawItemStruct->itemState & ODS_FOCUS)))
             pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
     }
}

To achieve the transparency feature, it will be necessary to control the background painting too, by handling the WM_CTLCOLOR message:

HBRUSH CRadioListBox::CtlColor(CDC* pDC, UINT nCtlColor) 
{
    // If transparent style selected...
    if ( (GetExStyle()&WS_EX_TRANSPARENT) && nCtlColor==CTLCOLOR_LISTBOX)
        return (HBRUSH)::GetSysColorBrush(COLOR_BTNFACE);

    return NULL;
}

History

  • March 29th, 2005. First version.
  • April 6th, 2005. Added transparency feature.

License

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

Share

About the Author

Jaime Olivares
Architect Freelance (jaimeolivares.com)
Peru Peru


Computer Electronics professional, Software Architect and senior Windows C++ and C# developer with experience in many other programming languages, platforms and application areas including communications, simulation systems, PACS/DICOM (radiology), GIS, 3D graphics and HTML5-based web applications.
Currently intensively working with Visual C# 2013 and TFS.
Can be reached at http://www.jaimeolivares.com
Follow on   LinkedIn

Comments and Discussions

 
GeneralSome issues PinmemberGast12820-Jan-09 3:52 
Question.NET version? Pinmemberjdtemplet18-Apr-06 13:23 
AnswerRe: .NET version? PinmemberJaime Olivares23-Apr-07 19:31 
Generallist boxes Pinmembercjsin24-Apr-05 22:28 
hi all i'm new at this and i hope u all will bear with me...
i'm having a problem with list boxes, i want to enter data into an edit box and store them into a list box as a linked list.
 
can someone help plizzz.Rose | [Rose]
Question??? Interest ??? PinmemberKandjar29-Mar-05 15:54 
AnswerRe: ??? Interest ??? PinmemberRavi Bhavnani29-Mar-05 20:04 
AnswerRe: ??? Interest ??? Pinmemberjaime_olivares30-Mar-05 1:46 
AnswerRe: ??? Interest ??? PinmemberTeashirt27-Apr-05 5:35 
GeneralDrawFrameControl() PinmemberRavi Bhavnani29-Mar-05 12:32 
GeneralRe: DrawFrameControl() Pinmemberjaime_olivares29-Mar-05 13:02 
GeneralScrolling Focus = Selection -> Bad PinmemberBlake Miller29-Mar-05 11:14 
GeneralRe: Scrolling Focus = Selection -> Bad Pinmemberjaime_olivares29-Mar-05 11:29 

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 | Mobile
Web03 | 2.8.140827.1 | Last Updated 22 Dec 2007
Article Copyright 2005 by Jaime Olivares
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid