How to change specific row color in list control depending on text present in specific column?

126 Views Asked by At

I am using MFC function OnCustomDraw to change the text color of a row. But instead of specific row all the rows in list control gets red color. I have added condition also to check the text. In my listCtrl 7th column has passport details like "Yes" and "No". So if someone has "No" passport then only that row text should be red. Please help me on this. I am using below code.

void CMyListClass::OnCustomdrawMyList(NMHDR* pNMHDR, LRESULT* pResult)
{
    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);

    *pResult = CDRF_DODEFAULT;

    if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
    {
        *pResult = CDRF_NOTIFYITEMDRAW;
    }
    else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
    {
        COLORREF crText;

        int nCol = 6;
        CString m_SearchThisItemText = _T("No");

        for (int i = 0; i < m_list.GetItemCount(); ++i)
        {
            CString szText = m_list.GetItemText(i, nCol);
            if (szText == m_SearchThisItemText)
            {
                crText = RGB(255, 0, 0);
                break;
            }
        }

        pLVCD->clrText = crText;

        *pResult = CDRF_DODEFAULT;
    }
}

I tried to fetch the subitem coloring but no success.

2

There are 2 best solutions below

1
xMRi On

You have to ask for the CDRF_NOTIFYSUBITEMDRAW and have to check for state CDDS_ITEMPREPAINT | CDDS_SUBITEM

if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
   *pResult  = CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYSUBITEMDRAW;  // request notifications for individual items
else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
   *pResult = CDRF_NOTIFYSUBITEMDRAW;     
else if ((CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage)
   ...

The code might be easier with a switch/case.

See sample here https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=24114

0
IInspectable On

The issue is here:

        for (int i = 0; i < m_list.GetItemCount(); ++i)
        {
            CString szText = m_list.GetItemText(i, nCol);
            if (szText == m_SearchThisItemText)
            {
                crText = RGB(255, 0, 0);
                break;
            }
        }

This iterates over all items and checks whether any match the predicate. If a single item matches the predicate, all rows will be rendered using red text color.

What you need to do instead is evaluate the current item only. The current item index is provided through the dwItemSpec field of the NMCUSTOMDRAW structure.

The following fixes your code:

        int i = static_cast<int>(pLVCD->nmcd.dwItemSpec);
        CString szText = m_list.GetItemText(i, nCol);
        if (szText == m_SearchThisItemText)
        {
            pLVCD->clrText = RGB(255, 0, 0);
        }