FIX: CCheckListBox Fails with Style LBS_MULTICOLUMN

ID: Q142960


The information in this article applies to:
  • The Microsoft Foundation Classes (MFC), included with:
    • Microsoft Visual C++, 32-bit Editions, 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

  1. 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.


  2. Add a protected member variable of type int called m_nCheckWidth to the new class.


  3. 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);
        } 


  4. 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);
        } 


  5. 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.

Additional query words: kbVC400bug 4.00 4.10 vcfixlist420

Keywords : kbcode kbMFC KbUIDesign kbVC
Version : 4.00 4.10
Platform : NT WINDOWS
Issue type :


Last Reviewed: July 29, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.