Sheen Space

Custom drawing selected item rows in Windows List-View Control

leave a comment »


This is code snippet to demonstrate how I redraw subitems in selected item rows in List-View Control. Although MFC is rarely used in GUI development today, I record code solution here for the benefit of minority.

Background is that, Windows Common Control provides generic way to let us do custom drawing, that is to handle custom draw in notification handler of NM_CUSTOMDRAW. (See http://msdn.microsoft.com/en-us/library/bb761817(v=vs.85).aspx)

However, in List-View control, when item’s state is “selected”, that item is always white text in blue background. Custom draw code can’t override the effect. To solve this problem, we have to do entire custom drawing in the message handler. In case CDDS_ITEMPREPAINT, instead of passing drawing to subitem stage CDDS_SUBITEM | CDDS_ITEMPREPAINT, we return CDRF_SKIPDEFAULT, and draw entire item manually.

case CDDS_ITEMPREPAINT:
	{
		// lplvcd is pointer to NMLVCUSTOMDRAW structure
		int itemIndex = lplvcd->nmcd.dwItemSpec;

		// Can't use (lplvcd->nmcd.uItemState | CDIS_SELECTED) to tell whether item is selected
		// when List-View control has style LVS_SHOWSELALWAYS.
		// See http://msdn.microsoft.com/en-us/library/bb775483(v=vs.85).aspx
		UINT selectState = GetItemState(itemIndex, LVIS_SELECTED);
		if (selectState == LVIS_SELECTED)
		{
			CDC dc;
			if (dc.Attach(lplvcd->nmcd.hdc))
			{
				DrawSelectedItem(dc, itemIndex);
				dc.Detach();
			}
			*pResult = CDRF_SKIPDEFAULT;
		}
		else
			*pResult = CDRF_NOTIFYSUBITEMDRAW;
	}
	break;
void CMyListCtrl::DrawSelectedItem( CDC& dc, int nIndex )
{
	int subitemCount = GetHeaderCtrl().GetItemCount();
	CRect itemRect;
	for (int i = 0; i < subitemCount; i++)
	{
		if (i == 0)
		{
			CalculateItemRect(nIndex, itemRect);
		}
		else if (!GetSubItemRect(nIndex, i, LVIR_BOUNDS, itemRect))
		{
			return;
		}

		// Adjust text rect to not overlap with grid lne and leave some space
		itemRect.DeflateRect(6, 0);
		dc.DrawText(GetItemText(nIndex, i), itemRect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
	}
}

void CMyListCtrl::CalculateItemRect( int nIndex, CRect& rect )
{
	// Calculate item head subitem(index = 0) rect
	// GetSubItemRect() returns rect of entire row for subitem 0
	if (GetSubItemRect(nIndex, 0, LVIR_BOUNDS, rect))
	{
		CRect nextRect;
		if (GetSubItemRect(nIndex, 1, LVIR_BOUNDS, nextRect))
			rect.right = nextRect.left;
	}
}
Advertisements

Written by Ying

07/01/2011 at 09:44

Posted in C++, Technology, Windows

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: