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

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • IT decision support impacts all aspects of technology management, from governance and strategy to budgets and resource planning. IT decision support effectiveness often falls prey to data-driven challenges that make it difficult to understand the data in context. These challenges: overwhelming data volumes, heterogeneous data types, and growing data complexity. This Forrester Consulting Paper reports the three key findings from their study conducted, on behalf of BDNA, to test the hypothesis that data …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds