January 13th, 2014

Creating a listview with checkboxes on some items but not others

Today’s Little Program creates a listview with checkboxes on some items but not other.

The LVS_EX_CHECK­BOXES extended style is really just a convenience style. Everything it does you could have done yourself, with a bit more typing.

  • It creates a state image list consisting of an unchecked box (state 1) and a checked box (state 2). You could have done this yourself with Image­List_Create followed by a few calls to Draw­Frame­Control.

  • When you hit the space bar or click on the check box, the state image toggles between 1 and 2. You could have done this yourself by responding to LVN_KEY­DOWN (for the space bar), and the mouse notification messages for the clicks. (For the mouse notifications, see if the click was on LVHT_ON­ITEM­STATE­ICON.)

But still, it’s convenient having the listview control do this grunt work for you. But what if you want to remove the check box from some items?

The listview control turns on the state image and toggles it by doing the moral equivalent of a List­View_Set­Check­State on the item, so all you have to do is respond to the LVN_ITEM­CHANGING that comes with any item change and reject the state change.

Start with our scratch program and make these changes. Remember, Little Programs do little or no error checking.

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
  g_hwndChild = CreateWindow(WC_LISTVIEW, NULL,
        WS_CHILD | WS_VISIBLE | LVS_REPORT,
        0, 0, 0, 0, hwnd, (HMENU)1, g_hinst, 0);
  ListView_SetExtendedListViewStyle(g_hwndChild,
                                    LVS_EX_CHECKBOXES);
  LVCOLUMN col;
  col.mask = LVCF_TEXT | LVCF_WIDTH;
  col.cx = 200;
  col.pszText = TEXT("Name");
  ListView_InsertColumn(g_hwndChild, 0, &col);
  LVITEM item;
  item.mask = LVIF_TEXT;
  item.iSubItem = 0;
  item.pszText = TEXT("Alpha");
  ListView_InsertItem(g_hwndChild, &item);
  item.pszText = TEXT("Beta");
  ListView_InsertItem(g_hwndChild, &item);
  item.pszText = TEXT("Gamma");
  ListView_InsertItem(g_hwndChild, &item);
  item.pszText = TEXT("Delta");
  ListView_InsertItem(g_hwndChild, &item);
  return TRUE;
}

Okay, so far the program adds four items, each with a check box. But let’s say we want to remove the check boxes from the even-numbered items.

LRESULT
OnNotify(HWND hwnd, int idFrom, NMHDR *pnm)
{
  if (idFrom == 1) {
    switch (pnm->code) {
    case LVN_ITEMCHANGING:
      {
        LPNMLISTVIEW pnmlv = CONTAINING_RECORD(pnm, NMLISTVIEW, hdr);
        if (pnmlv->iItem >= 0 &&
        if (pnmlv->iItem % 2 == 0 &&
            (pnmlv->uChanged & LVIF_STATE)) {
         return TRUE; // reject changes to even-numbered items
        }
      }
      break;
    }
  }
  return 0;
}
    HANDLE_MSG(hwnd, WM_NOTIFY, OnNotify);

We add a handler for LVN_ITEM­CHANGING that says, “If this is a notification for an even-numbered item, and they want to change the state, then block the state change.” This ensures that nobody can turn on the state image, which means that the checkbox never shows up.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.