![]() |
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. |
![]() |
Able to be used without instantiating class - this was important, because I necessarily have to minimize the impact on existing code. |
![]() |
Able to be used without recoding or redefining existing control variables - again, for same reasons as previous point. |
![]() |
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() // // 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; }
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:
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.
To integrate EnableGroupboxControls into your app, you first need to add following files to your project:
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
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.