Search code examples
visual-c++mfcclistctrl

Is there a way to override the handler called when a user clicks a checkbox in a CListCtrl? (MFC)


I am trying to disable the user's ability to alter the state of a checkbox in a List Control. I am currently changing the state pragmatically. I already handle the LVN_ITEMCHANGED message, and trying to alter the state there isn't an option due to the layout of the rest of the program. I have also tried doing a HitTest when the user clicks in the List Control and simply resetting the checkbox there but that isn't giving me the exact results I am looking for.

Is there a specific message sent or a function I can override when the user clicks the checkbox itself? I would just like to override the handler or catch the message so that it doesn't go anywhere.


Solution

  • Solution:

    I ended up removing the LVS_EX_CHECKBOXES flag and created my own implementation. That way the there is only one way to change the icons. Reading the link from the previous question gave me an idea to set a "busy" flag, otherwise I would get stack overflow errors.

    // In my dialog class
    m_CListCtrl.SetImageList(&m_ImgList, LVSIL_SMALL);    // Custom checkboxes (only two images)
    
    // ...
    void CMyDialog::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
    {
       if(busy) { return; }
       // ....
    } 
    
    // When calling the SetCheck function:
    busy = TRUE;   // Avoid stack overflow errors
    m_CListCtrl.SetCheck(index, fCheck);
    busy = FALSE;
    
    // I derived a class from CListCtrl and did an override on the get/set check:
    class CCustomListCtrl : public CListCtrl
    {
        BOOL CCustomListCtrl::SetCheck(int nItem, BOOL fCheck)
        {
            TCHAR szBuf[1024];
            DWORD ccBuf(1024);
            LVITEM lvi;
            lvi.iItem = nItem;
            lvi.iSubItem = 0;
            lvi.mask = LVIF_TEXT | LVIF_IMAGE;
            lvi.pszText = szBuf;
            lvi.cchTextMax = ccBuf;
            GetItem(&lvi);
            lvi.iImage = (int)fCheck;
            SetItem(&lvi);
            return TRUE;
        }
        // Just need to determine which image is set in the list control for the item
        BOOL CCustomListCtrl::GetCheck(int nItem)
        {
            LVITEM lvi;
            lvi.iItem = nItem;
            lvi.iSubItem = 0;
            lvi.mask = LVIF_IMAGE;
            GetItem(&lvi);
            return (BOOL)(lvi.iImage);
        }
    }
    

    This is not as elegant as I had hoped, but it works flawlessly.