MFC Radio Group control like Delphi

Ever worked with Borland Delphi or Borland C Builder? You might have noticed the Radio Group Control that OWL presents (OWL is Object Windows Library ? Borland’s windows Win32 class wrapper library something like MFC).

So here is a project that gives an example of how this control may be created with MFC. The customized MFC class created here is called CRadioGroup and is kept in the files RadioGroup.h and RadioGroup.cpp.

Using the Radio Button Control in MFC:

The control must be always created dynamically ? using its Create method, like this:

your_rg_instance.Create(?Title for the Group?, rect, WS_CHILD|WS_VISIBLE|BS_GROUPBOX, parent, ID);

Here is a list of the specific methods that were implemented for this control:

BOOL Create(CString lpzsCaption, DWORD dwStyle, const CRect& rect, CWnd* parent, UINT nId);

Creates the control.

void redraw(bool bRecreate = false);

Redraws the control?s items and, if specified, (re)creates them. This is mainly for internal use.

void setCaption(const CString& cap);

Changes the caption of the control

CString caption();

Retrieves the caption of the control.

void addItem(const CString& str, int pos);

Adds an item at a specified positon

void removeItem(int Pos);

Removes the item at the specified position.

void removeAll();

Removes all items from the group.

int getSel() const;

Retrieves the item that is currently selected. (-1 if none is)

void setSel(unsigned int pos);

Sets the currently selected item (Set -1 to lose every selection)

bool isSel(int pos) const;

Shows if the item at the specified position is selected.

CString getTextAt(int pos) const;

Gets the text of the item at the specified position.

void setAutoAlign(bool b);

Sets the vertical space between the items in the control to be self-evaluated. This flag is set by default.

void setHSpace(int h);

Sets the space in pixels between the items and the left border of the control.

void setVSpace(int v);

Sets the vertical space in pixels between the items. Ignored when Auto-Align is set.

void setTopSpace(int t);

Sets the space in pixels between the top border of the control and the first item.

int getVSpace() const;

Retrieves the space in pixels between the items.

int getHSpace() const;

Retrieves the space in pixels between the items and the left border of the control.

int getTopSpace() const;

Retrieves the space in pixels between the top border of the control and the first item.

bool autoAlign() const;

Shows if the control is set to auto-align.

int numItems() const;

Retrieves the number of items in the radio group.

void enableItem(int nPos, bool bEnable);

Enables/Disables the item at the specified position.

When the selection in the radio group is changed it raises a windows message that is defined in the header file of the class – WM_RADIOGROUPSELCHANGE. To handle this message add to the message map of the parent class the following line

ON_MESSAGE(WM_RADIOGROUPSELCHANGE, RGSelChangeProc)

where RGSelChangeProc is a member function declared like this:

afx_msg LRESULT RGSelChangeProc(WPARAM nId, LPARAM);

In the body of the function you will receive the id of the specific radio group as the first parameter. The second one is not used.

Development of this Radio Button Control:

We need to make a dialog-on-the-dialog sort of speak because the radio group is actually a number of different controls ? frame, and radio buttons. The best way to accomplish this is use the property page control (CPropertyPage), which is supposed to be put on a dialog as a child control, but is derived from CDialog and controls can be placed on it. So the CRadioGroup class is derived from CPropertyPage. But here we meet the first problem ? to create a property page you need a dialog template in your application?s resources. So in order to have radio groups on your dialogs you must do the following:

  1. Create a new dialog template with id: IDD_RGDLG
  2. Set the style of the template to “child”
  3. Set the border to “none”
  4. Uncheck all styles
  5. Check only the ?Visible? style.

For easier internal use we created the structure RadElement, and the class CChildRadioButton. The structure contains various data about each item of the radio group and the class is derived from CButton and is used to handle its own click messages and resend them to the radio group so it can handle them properly and if needed send a message to the parent.

All items from the group are stored in an array of RadElement. This array is used to get the information needed for each item.

The purpose of the redraw function:

Each time you change the spaces in the group with setHSpace, setVSpace, setTopSpace, setAutoAlign the buttons are not automatically redrawn you must call redraw to update the changes on the control. When you add items in some point of the program when the control is created, you must call the function to draw the new items. Also when the control is sized this function is called internally.

You might add items to the control even before it is created, so when it is created the functions is called with the parameter set to true to create the items (not only redraw them). So do not call redraw(true) during runtime! This call is reserved for internal use only.

In order for the radio group to function properly all buttons must have id?s that are ordinal numbers. That?s why the addItem function changes the ids of all buttons to be ordinal.

So basically the class creates a property page and on it, it creates a frame for the group, the inside the frame it creates the items that are radio buttons. You can change everything on the class dynamically. The class is almost an exact copy of OWL?s radio group.

The sample project shows two radio groups on a dialog. When the selection of either group is changed the message is handled and this is shown on the dialog.

To use the radio group in you projects add the files (RadioGroup.h, RadioGroup.cpp) to your project and do not forget to create the empty dialog as shown above.

Attachments:

Source Files: RadioGroup.zip

Project Files: RadioGroupProject.zip