Why Standard Controls Need Owner-Draw
Standard Windows controls (buttons, list boxes, combo boxes, list controls) render themselves using default system visuals, which is fine until you need per-item icons, colored status indicators, variable-height rows, or a custom-styled button. Owner-draw is the mechanism by which the control delegates its own painting back to the parent window (the 'owner'): you set the control's style to include owner-draw (e.g., BS_OWNERDRAW for a button, LBS_OWNERDRAWVARIABLE for a list box) and MFC then routes drawing requests to virtual functions like CButton::DrawItem or CListBox::DrawItem that you override.
Cricket analogy: Like a franchise handing full creative control of the pre-match light show to an external production company instead of using the stadium's default announcement system, owner-draw hands rendering control from the default control to your own DrawItem override.
Implementing DrawItem for a List Box
When a list box is styled LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE, Windows sends WM_DRAWITEM for each visible item, which MFC forwards to CListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct). The structure carries the item's index, its rectangle (rcItem), and its state flags (ODS_SELECTED, ODS_FOCUS) so you can, for instance, fill a different background color for a selected row before drawing the item's text or icon on top — and for LBS_OWNERDRAWVARIABLE you must also override MeasureItem to report each item's height since rows are no longer uniform.
Cricket analogy: Like the broadcast graphics team checking whether a batter is 'on strike' (a state flag) before highlighting their name differently on the scorecard, DrawItem checks ODS_SELECTED to decide whether to highlight that row's background.
NM_CUSTOMDRAW for Common Controls
Modern common controls like CListCtrl and CTreeCtrl support a finer-grained mechanism than classic owner-draw: custom draw, delivered via WM_NOTIFY with an NM_CUSTOMDRAW structure across multiple drawing stages (CDDS_PREPAINT, CDDS_ITEMPREPAINT, CDDS_ITEMPOSTPAINT). You return a combination of CDRF_NOTIFYITEMDRAW and similar flags to tell the control which stages you want to intercept, letting you, for example, change only a subitem's text color while leaving the control to draw the rest of its chrome (gridlines, selection rectangle, focus rectangle) itself — a much lighter-weight approach than fully replacing DrawItem.
Cricket analogy: Like a third umpire only reviewing the specific moment of a run-out at the crease rather than re-officiating the entire over, custom draw lets you intercept just the CDDS_ITEMPREPAINT stage rather than repainting the whole control.
void CMyListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CRect rc(lpDIS->rcItem);
BOOL bSelected = (lpDIS->itemState & ODS_SELECTED) != 0;
pDC->FillSolidRect(&rc, bSelected ? RGB(0, 120, 215) : RGB(255, 255, 255));
CString strText;
GetText(lpDIS->itemID, strText);
pDC->SetTextColor(bSelected ? RGB(255, 255, 255) : RGB(0, 0, 0));
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(strText, &rc, DT_SINGLELINE | DT_VCENTER | DT_LEFT);
if (lpDIS->itemState & ODS_FOCUS)
pDC->DrawFocusRect(&rc);
}For simple cases like custom text color or a custom background per row in a CListCtrl, prefer NM_CUSTOMDRAW over full owner-draw: it lets the control keep handling gridlines, headers, and selection rectangles for you, which means less code and fewer visual inconsistencies compared to a full DrawItem override where you're responsible for every pixel.
- Owner-draw hands rendering responsibility for a control from its default painting to a DrawItem override you write.
- Buttons use BS_OWNERDRAW; list boxes use LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE.
- LPDRAWITEMSTRUCT provides the item's rectangle, index, and state flags like ODS_SELECTED and ODS_FOCUS.
- LBS_OWNERDRAWVARIABLE requires also overriding MeasureItem to report per-item heights.
- Modern common controls support NM_CUSTOMDRAW via WM_NOTIFY, offering staged, lighter-weight paint interception.
- NM_CUSTOMDRAW return flags like CDRF_NOTIFYITEMDRAW control which paint stages get delivered next.
- Prefer custom draw over full owner-draw when you only need to tweak specific visual details, not replace all rendering.
Practice what you learned
1. Which button style enables owner-draw for a CButton?
2. What additional virtual function must be overridden alongside DrawItem when using LBS_OWNERDRAWVARIABLE?
3. What does the ODS_SELECTED flag in an item's state indicate?
4. What notification message delivers NM_CUSTOMDRAW information to a window?
5. Why might a developer prefer NM_CUSTOMDRAW over full owner-draw for a CListCtrl?
Was this page helpful?
You May Also Like
Drawing with CDC
A practical tour of the CDC drawing API — lines, shapes, text, and pens/brushes — and the conventions MFC applications follow to render correctly inside OnDraw and OnPaint.
GDI Basics in MFC
An introduction to the Windows Graphics Device Interface (GDI) and how MFC's CDC class family wraps device contexts, handles, and GDI objects for safe, structured drawing.
Double Buffering in MFC
Why complex or frequently updated views flicker under naive GDI drawing, and how to eliminate that flicker using an off-screen memory device context in MFC.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics
Microsoft TechnologiesMVVM Design Pattern Study Notes
.NET · 30 topics