Click here to Skip to main content
15,881,139 members
Articles / Desktop Programming / MFC

CRadioListBox: A ListBox with Radio Buttons (MFC version)

Rate me:
Please Sign up or sign in to vote.
4.79/5 (16 votes)
22 Dec 2007CPOL2 min read 132.8K   4.3K   54   12
How to implement an owner-drawn ListBox with radio buttons instead of standard selection highlight
Image 1

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:

C++
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:

C++
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:

C++
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)


Written By
Architect
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 Studio and TFS.

Comments and Discussions

 
GeneralSome issues Pin
Gast12820-Jan-09 3:52
Gast12820-Jan-09 3:52 
Question.NET version? Pin
jdtemplet18-Apr-06 13:23
jdtemplet18-Apr-06 13:23 
AnswerRe: .NET version? Pin
Jaime Olivares23-Apr-07 19:31
Jaime Olivares23-Apr-07 19:31 
Generallist boxes Pin
cjsin24-Apr-05 22:28
cjsin24-Apr-05 22:28 
Question??? Interest ??? Pin
Kandjar29-Mar-05 15:54
Kandjar29-Mar-05 15:54 
AnswerRe: ??? Interest ??? Pin
Ravi Bhavnani29-Mar-05 20:04
professionalRavi Bhavnani29-Mar-05 20:04 
I believe it's a single selection variant of a CCheckListBox. Checking an item in the list box is different from highlighting it.

/ravi

My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com

AnswerRe: ??? Interest ??? Pin
Jaime Olivares30-Mar-05 1:46
Jaime Olivares30-Mar-05 1:46 
AnswerRe: ??? Interest ??? Pin
Teashirt27-Apr-05 5:35
Teashirt27-Apr-05 5:35 
GeneralDrawFrameControl() Pin
Ravi Bhavnani29-Mar-05 12:32
professionalRavi Bhavnani29-Mar-05 12:32 
GeneralRe: DrawFrameControl() Pin
Jaime Olivares29-Mar-05 13:02
Jaime Olivares29-Mar-05 13:02 
GeneralScrolling Focus = Selection -> Bad Pin
Blake Miller29-Mar-05 11:14
Blake Miller29-Mar-05 11:14 
GeneralRe: Scrolling Focus = Selection -> Bad Pin
Jaime Olivares29-Mar-05 11:29
Jaime Olivares29-Mar-05 11:29 

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

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