Enabling/Disabling a Group of Controls

Overview

The MFC FAQ "Item 6.3.5. How do I enable/disable a bank of checkboxes?" discusses a technique for enabling/disabling a "bank" of check boxes. I would like to present a method of enabling/disabling a "Group" of controls.

Background

If a control uses the WS_GROUP style, it "Specifies the first control of a group of controls in which the user can move from one control to the next by using the arrow keys. All controls in the tab order after the first control with the Group property set to False belong to the same group. The next control in the tab order with Group set to True ends the first group of controls and starts the next group. Type: Bool. Default: False"[1]. A "Group Box" control is often used to group controls, with the Group Box having the WS_GROUP style.

Design

The method of enabling/disabling a Group of controls presented here simply iterates thru the controls in a Group enabling/disabling each control as it is encountered. Unfortunately, the MFC CWnd::GetNextDlgGroupItem() method is not suitable for this task because it skips over controls that are not enabled[2]. The technique presented here derives a new class from CDialog named CDialogEx, and adds two methods CDialogEx::EnableDlgGroup() and CDialogEx::GetNextDlgGroupItemEx(). These functions are prototyped as follows:


BOOL	CDialogEx::EnableDlgGroup(int nDlgItemId, BOOL fEnable);
CWnd	* CDialogEx::GetNextDlgGroupItemEx(CWnd *pCtrlWnd);

Implementation

CDialogEx::EnableDlgGroup() and CDialogEx::GetNextDlgGroupItemEx() are simple wrappers for the lower level functions CWnd_EnableDlgGroup() and CWnd_GetNextDlgGroupItemEx(). CDialogEx was implemented this way so the user may also use CWnd_EnableDlgGroup() and CWnd_GetNextDlgGroupItemEx() directly (instead of always having to derive a new class from CDialogEx).

CDialogEx::EnableDlgGroup() and CDialogEx::GetNextDlgGroupItemEx() are defined as follows:


BOOL	CDialogEx::EnableDlgGroup(int nDlgItemId, BOOL fEnable)
{
	// nDlgItemId is typically the resource id of 
	// a (Group Box) control with WS_GROUP style
	return CWnd_EnableDlgGroup(this, nDlgItemId, fEnable);
}

CWnd	*CDialogEx::GetNextDlgGroupItemEx(CWnd *pCtrlWnd)
{
	return CWnd_GetNextDlgGroupItemEx(pCtrlWnd);
}

CWnd_EnableDlgGroup() and CWnd_GetNextDlgGroupItemEx() are defined as follows:


BOOL	CWnd_EnableDlgGroup(CWnd *pDlgWnd, int nDlgItemId, BOOL fEnable)
{
	CWnd	*pCtrlWnd;

	if (pDlgWnd == NULL
	|| (pCtrlWnd = pDlgWnd->GetDlgItem(nDlgItemId)) == NULL)
	{
		return FALSE;
	}

	do
	{
		pCtrlWnd->EnableWindow(fEnable);
	} while ((pCtrlWnd = CWnd_GetNextDlgGroupItemEx(pCtrlWnd)) != NULL);

	return TRUE;
}

CWnd	*CWnd_GetNextDlgGroupItemEx(CWnd *pCtrlWnd)
{
	CWnd	*pWnd;

	if (pCtrlWnd == NULL
	|| pCtrlWnd->GetDlgCtrlID() == 0
	|| (pWnd = pCtrlWnd->GetWindow(GW_HWNDNEXT)) == NULL
	|| (pWnd->GetStyle() & WS_GROUP))
	{
		return NULL;
	}

	return pWnd;
}

Test Application

The source for CDialogEx along with a test project is included. The test project is an MFC App Wizard Dialog based application built using MSVC 5.0 with SP3 applied. It's main window is a dialog box derived from CDialogEx. The dialog box contains two check boxes and two group boxes. Checking a check box enables/disables the controls in it's associated group box.

References

[1] MS Windows Win32 SDK online help

[2] MS Knowledge Base article Q114980

Download CDialogEx source code and demo project - 11 KB



Comments

  • How to disable List Ctrl by having full scroll functionalitiy?

    Posted by Legacy on 07/16/2001 12:00am

    Originally posted by: stephan

    Good,
    but do you know how to disable a List Ctrl by having
    enabled scrolling?

    Reply
  • Nested groups. Advanced function.

    Posted by Legacy on 11/30/1999 12:00am

    Originally posted by: Eugene N. Nepomnyashchiy

    I think so:
    
    

    EnableDlgGroup declaration:

    BOOL EnableDlgGroup( HWND hDlg, BOOL bEnable, UINT nIDGroupStart, UINT nGroupEnd = 0 )

    1. To enable group with nested groups make call:

    EnableDlgGroup( hDlg, bEnable, nIDGroupStart, nIDGroupEnd )

    where:
    nIDGroupStart - id of first item (e.g. GroupBox);
    nIDGroupEnd - id of the item follows past item in the group

    2. To enable single group make call:

    EnableDlgGroup( hDlg, bEnable, nIDGroupStart )

    where:
    nIDGroupStart - id of first item (e.g. GroupBox);

    EnableDlgGroup function body:

    BOOL EnableDlgGroup( HWND hDlg, BOOL bEnable, UINT nIDGroupStart, UINT nGroupEnd = 0 )
    {
    if (!hDlg) return FALSE;
    HWND hItem = GetDlgItem( hDlg, nIDGroupStart );
    while (hItem)
    {
    EnableWindow( hItem, bEnable );
    hItem = GetNextWindow( hItem, GW_HWNDNEXT );
    if (hItem)
    {
    if (nGroupEnd)
    {
    if ( GetWindowLong( hItem, GWL_ID ) == (LONG)nGroupEnd ) hItem = NULL;
    }
    else
    {
    if ( GetWindowLong( hItem, GWL_STYLE ) & WS_GROUP ) hItem = NULL;
    }
    }
    }
    return FALSE;
    }

    Reply
  • Enabling/Disabling a group of controls

    Posted by Legacy on 05/17/1999 12:00am

    Originally posted by: Charlie Curtis

    I have been able to incorporate your code into my application, but would like to ask for a little assistance as I can't make it function the way I want it to. You have used check boxes to enable/disable and I would like to do something a little bit different. When my initial dialog box opens. I have 5 edit boxes for user input. A combo box I am using for a Month selector. A spin button control that is used for a 4 digit numeric year selection (1994 - 1999). 3 radio buttons for specifying the type of data to be retrieved and finally a pushbutton for retrieving the requested data.
    Now what I would like to accomplish is getting the group of radio buttons disabled when the application starts. Then stay that way until the spin button is changed to a year less than the current year. This is so the user knows that they have to input data in the edit boxes correctly or
    they will not get what they want.
    I have tried following the code you supplied and do alright until your onCheck1() function. It only has UpdateData(TRUE); EnableDlgGroup(IDC_GROUP1, !m_fCheck1); these two statements and what I did was in my InitDialog() add the same but tried to force the !m_fCheck1 to TRUE and then FALSE, but it didn't work. So I have missed something and can't put my finger on it. So I would greatly appreciate any assistance that you might provide.
    Anyone else who might know of a solution is welcome to respond as well!

    Thanks Charlie Curtis

    Reply
  • Destructor should be virtual

    Posted by Legacy on 02/06/1999 12:00am

    Originally posted by: Keller Beyer

    Since CDialogEx is intended to be used as a base class,
    
    it's destructor should be virtual, e.g.
    class CDialogEx : public CDialog
    {
    public:
    ...
    virtual ~CDialogEx();
    ...
    };

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds