EnableGroupboxControls - a non-MFC function to enable or disable all the controls within a groupbox

Introduction

EnableGroupboxControls is a function I have used in several projects, where I wanted to enable/disable all the controls within a groupbox. There are several other solutions to this problem here on CodeProject - I have included a list here. None of these, however, had everything I was looking for:
screenshot Able to be used in MFC or non-MFC project - since I spend a lot of time maintaining older Windows applications, I wanted a very lightweight solution.
screenshot Able to be used without instantiating class - this was important, because I necessarily have to minimize the impact on existing code.
screenshot Able to be used without recoding or redefining existing control variables - again, for same reasons as previous point.
screenshot Able to accommodate nested groupboxes - many of the dialogs in apps I maintain are non-trivial, because the apps themselves are highly technical. Nesting groupboxes is one way of coping with complex user interfaces.

EnableGroupboxControls API

Here is the EnableGroupboxControls function:
Collapse
//=============================================================================
//
// EnableGroupboxControls()
//
// Purpose:     This function enables/disables all the controls that are
//              completely contained with a groupbox.
//
// Parameters:  hWnd    - HWND of groupbox control
//              bEnable - TRUE = enable controls within groupbox
//
// Returns:     int     - number of controls enabled/disabled.  If zero is
//                        returned, it means that no controls lie within the
//                        rect of the groupbox.
//
int EnableGroupboxControls(HWND hWnd, BOOL bEnable)
{
int rc = 0;
if (::IsWindow(hWnd))
{
// get class name
TCHAR szClassName[MAX_PATH];
szClassName[0] = _T('\0');
::GetClassName(hWnd, szClassName, sizeof(szClassName)/sizeof(TCHAR)-2);
// get window style
LONG lStyle = ::GetWindowLong(hWnd, GWL_STYLE);
if ((_tcsicmp(szClassName, _T("Button")) == 0) &&
((lStyle & BS_GROUPBOX) == BS_GROUPBOX))
{
// this is a groupbox
RECT rectGroupbox;
::GetWindowRect(hWnd, &rectGroupbox);
// get first child control
HWND hWndChild = 0;
HWND hWndParent = ::GetParent(hWnd);
if (IsWindow(hWndParent))
hWndChild = ::GetWindow(hWndParent, GW_CHILD);
while (hWndChild)
{
RECT rectChild;
::GetWindowRect(hWndChild, &rectChild);
// check if child rect is entirely contained within groupbox
if ((rectChild.left >= rectGroupbox.left) &&
(rectChild.right <= rectGroupbox.right) &&
(rectChild.top >= rectGroupbox.top) &&
(rectChild.bottom <= rectGroupbox.bottom))
{
//TRACE(_T("found child window 0x%X\n"), hWndChild);
::EnableWindow(hWndChild, bEnable);
rc++;
}
// get next child control
hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
}
// if any controls were affected, invalidate the parent rect
if (rc && IsWindow(hWndParent))
{
::InvalidateRect(hWndParent, NULL, FALSE);
}
}
}
return rc;
}

EnableGroupboxControls Demo

The EnableGroupboxControls demo app shows how controls inside a groupbox may be enabled/disabled:

screenshot

When the checkbox for groupbox 1 is unchecked, all the controls inside groupbox 1 and groupbox 2 are disabled:

screenshot

Here is the code that manages these nested groupboxes:
void CEnableGroupboxControlsTestDlg::OnCheck1()
{
UpdateData(TRUE);
EnableGroupboxControls(::GetDlgItem(m_hWnd, IDC_GROUPBOX_1), m_bCheck1);
// enable controls within embedded groupbox
OnCheck2();
}
void CEnableGroupboxControlsTestDlg::OnCheck2()
{
UpdateData(TRUE);
EnableGroupboxControls(::GetDlgItem(m_hWnd, IDC_GROUPBOX_2), m_bCheck1 && m_bCheck2);
}
Note that there is no linkage between the checkboxes and the groupboxes except what you see in the above code. The two groupboxes are created in the dialog template with a field of spaces (instead of text). Then checkboxes are created and overlaid on the groupbox, so that the visual appearance is that of a groupbox "controlled" by a checkbox. Here is dialog template for demo app, with the two checkbox/combobox pairs highlighted:

screenshot

Overlaying the groupbox header with a checkbox will work only if you know the trick: the groupbox must precede the checkbox in tab order. Tab order is simply the order in which controls appear in the dialog template. If the groupbox came after the checkbox, it would overlay the checkbox, and the checkbox would not be visible to the user. This works this way because the order of controls in the dialog template is also the order in which the controls are created and displayed at run time.
You can set the tab order inside Visual Studio, but with overlapping controls it is not completely straightforward. Here is what the dialog template looks like in VS2005, with tab order labels made visible by menu command Format | Tab Order:

screenshot

The two groupbox headers that are outlined in red are the ones that have been overlaid by checkboxes. Since the tab order labels for 1 and 2, and 8 and 9, are displayed over each other, it is difficult to set the tab order in VS IDE. However, as usual, there is a trick: temporarily move the checkboxes above or below the groupbox, and then edit the tab order. When you are finished, move checkboxes back.

Of course, it is not necessary to have checkbox in groupbox header, in order to make use of EnableGroupboxControls. The button labelled Disable Groupbox 3 is an example of how to do this.

How to use

Step 1 - Add Files

To integrate EnableGroupboxControls into your app, you first need to add following files to your project:

  • EnableGroupboxControls.cpp
  • EnableGroupboxControls.h

The .cpp file should be set to Not using precompiled header in Visual Studio. Otherwise, you will get error

    fatal error C1010: unexpected end of file while looking for precompiled header directive

Step 2 - Add Header File to Your Source Module

In the module where you want to use EnableGroupboxControls, include header file EnableGroupboxControls.h .

Step 3 - Add Code

When user clicks a checkbox (or makes some kind of selection). add code like I have shown above, to call EnableGroupboxControls function.

References

Here are some other articles that discuss managing controls within a groupbox:

Revision History

Version 1.0 - 2008 April 9

  • Initial public release

Usage

This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

posted @ 2008-08-13 13:18  广陵散仙(www.cnblogs.com/junzhongxu/)  阅读(630)  评论(0编辑  收藏  举报