4.00 4.10
WINDOWS NT
kbprg kbbuglist kbcode kbfixlist
The information in this article applies to:
- The Microsoft Foundation Classes (MFC) included with:
Microsoft Visual C++, 32-bit Edition, versions 4.0, 4.1
SYMPTOMS
When using the CCheckListBox class and specifying a style of
LBS_MULTICOLUMN, the user will be unable to check or uncheck items that
are not displayed in the first column.
CAUSE
The hit-testing that is done in CCheckListBox::OnLButtonDown does not take
into consideration which column the user is clicking.
RESOLUTION
Derive a class from CCheckListBox and override OnLButtonDown to do proper
hit-testing. It will also be necessary to override OnLButtonDblClk and the
constructor.
Step-by-Step Example
- Bring up ClassWizard. Use "Add Class" to add a new class called
CMyCheckListBox derived from CListBox. In the .h and .cpp files
generated for the new class, change all occurrences of CListBox
to CCheckListBox.
- Add a protected member variable of type int called m_nCheckWidth
to the new class.
- Modify the default constructor for CMyCheckListBox to look like this:
CMyCheckListBox::CMyCheckListBox()
{
// the following code initializes the member variable
// m_nCheckWidth to be the width of a check box.
CBitmap bitmap;
BOOL bWin4 = (BYTE)GetVersion() >= 4;
HINSTANCE hInst = bWin4 ? NULL : LoadLibraryA("CTL3D32.DLL");
FARPROC pfnProc = (NULL == hInst) ? NULL : GetProcAddress(hInst,
(LPCSTR)21);
if (bWin4 || pfnProc != NULL)
VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_95));
else
VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_NT));
BITMAP bm;
bitmap.GetObject(sizeof (BITMAP), &bm);
m_nCheckWidth = bm.bmWidth / 3;
if (hInst)
FreeLibrary(hInst);
}
- Use ClassWizard to add a handler for WM_LBUTTONDOWN, and implement it
as follows:
void CMyCheckListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect itemRect;
CRect clientRect;
GetClientRect(clientRect);
for(int nIndex = GetTopIndex(); nIndex < GetCount(); nIndex++)
{
GetItemRect(nIndex, &itemRect);
if (!clientRect.PtInRect(itemRect.TopLeft()))
break;
if (itemRect.PtInRect(point) && IsEnabled(nIndex))
{
if (m_nStyle != BS_CHECKBOX && m_nStyle != BS_3STATE)
{
if (point.x - itemRect.left < m_nCheckWidth + 2)
{
CWnd* pParent = GetParent();
ASSERT_VALID(pParent);
int nModulo = (m_nStyle == BS_AUTO3STATE) ? 3 : 2;
int nCheck = GetCheck(nIndex);
nCheck = (nCheck == nModulo) ? nCheck - 1 : nCheck;
SetCheck(nIndex, (nCheck + 1) % nModulo);
InvalidateCheck(nIndex);
CListBox::OnLButtonDown(nFlags, point);
// Inform of check
pParent->SendMessage(WM_COMMAND,
MAKEWPARAM(GetDlgCtrlID(), CLBN_CHKCHANGE),
(LPARAM)m_hWnd);
return;
}
}
else
return; // Swallow LButtons for disabled items
}
}
// call CListBox::OnLButtonDown
// DO NOT call CCheckListBox::OnLButtonDown
CListBox::OnLButtonDown(nFlags, point);
}
- Use ClassWizard to add a handler for WM_LBUTTONDDBLCLK and just call
CMyCheckListBox::OnLButtonDown:
void CMyCheckListBox::OnLButtonDblClk(UINT nFlags, CPoint point)
{
OnLButtonDown(nFlags, point);
}
STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed
at the beginning of this article. This problem was corrected in Visual C++,
32-bit Edition, version 4.2.
|