HOWTO: Make a List Box Item Unavailable for Selection

ID: Q74792


The information in this article applies to:


SUMMARY

In the Microsoft Windows graphical environment, an application can use a list box to enumerate options. However, there are circumstances in which one or more options may not be appropriate. The application can change the appearance of items in a list box and prevent the user from selecting one of these items by using the techniques discussed below.


MORE INFORMATION

Changing the Appearance of a List Box Item

To dim (gray) a particular item in a list box, use an owner-draw list box as follows:
  1. Create a list box that has the LBS_OWNERDRAW and LBS_HASSTRINGS styles.


  2. Use the following code to process the WM_MEASUREITEM message:
    
          case WM_MEASUREITEM:
             ((MEASUREITEMSTRUCT FAR *)(lParam))->itemHeight = wItemHeight;
             break;
     
    wItemHeight is the height of a character in the list box font.


  3. Use the following code to process the WM_DRAWITEM message:
    
          #define PHDC (pDIS->hDC)
          #define PRC  (pDIS->rcItem)
    
          DRAWITEMSTRUCT FAR *pDIS;
    
             ...
    
          case WM_DRAWITEM:
             pDIS = (DRAWITEMSTRUCT FAR *)lParam;
    
             /* Draw the focus rectangle for an empty list box or an
                empty combo box to indicate that the control has the
                focus
              */ 
             if ((int)(pDIS->itemID) < 0)
             {
                switch(pDIS->CtlType)
                {
                   case ODT_LISTBOX:
                      if ((pDIS->itemAction) & (ODA_FOCUS))
                         DrawFocusRect (PHDC, &PRC);
                      break;
    
                   case ODT_COMBOBOX:
                      if ((pDIS->itemState) & (ODS_FOCUS))
                         DrawFocusRect (PHDC, &PRC);
                      break;
                }
                return TRUE;
             }
    
             /* Get the string */ 
             switch(pDIS->CtlType)
             {
                case ODT_LISTBOX:
                   SendMessage ( pDIS->hwndItem,
                                 LB_GETTEXT,
                                 pDIS->itemID,
                                 (LPARAM)(LPSTR)szBuf);
                   break;
    
                case ODT_COMBOBOX:
                   SendMessage ( pDIS->hwndItem,
                                 CB_GETLBTEXT,
                                 pDIS->itemID,
                                 (LPARAM)(LPSTR)szBuf);
                   break;
             }
    
             if (*szBuf == '!')   // This string is disabled
             {
                hbrGray = CreateSolidBrush (GetSysColor
                                              (COLOR_GRAYTEXT));
                GrayString ( PHDC,
                             hbrGray,
                             NULL,
                             (LPARAM)(LPSTR)(szBuf + 1),
                             0,
                             PRC.left,
                             PRC.top,
                             0,
                             0);
                DeleteObject (hbrGray);
    
                /* SPECIAL CASE - Need to draw the focus rectangle if
                   there is no current selection in the list box, the
                   1st item in the list box is disabled, and the 1st
                   item has gained or lost the focus
                 */ 
                if (pDIS->CtlType == ODT_LISTBOX)
                {
                   if (SendMessage ( pDIS->hwndItem,
                                     LB_GETCURSEL,
                                     0,
                                     0L) == LB_ERR)
                      if ( (pDIS->itemID == 0) &&
                           ((pDIS->itemAction) & (ODA_FOCUS)))
                         DrawFocusRect (PHDC, &PRC);
                }
             }
    
             else  // This string is enabled
             {
                if ((pDIS->itemState) & (ODS_SELECTED))
                {
                   /* Set background and text colors for selected
                      item */ 
                   crBack = GetSysColor (COLOR_HIGHLIGHT);
                   crText = GetSysColor (COLOR_HIGHLIGHTTEXT);
                }
                else
                {
                   /* Set background and text colors for unselected
                      item */ 
                   crBack = GetSysColor (COLOR_WINDOW);
                   crText = GetSysColor (COLOR_WINDOWTEXT);
                }
    
                // Fill item rectangle with background color
                hbrBack = CreateSolidBrush (crBack);
                FillRect (PHDC, &PRC, hbrBack);
                DeleteObject (hbrBack);
    
                // Set current background and text colors
                SetBkColor (PHDC, crBack);
                SetTextColor (PHDC, crText);
    
                // TextOut uses current background and text colors
                TextOut ( PHDC,
                          PRC.left,
                          PRC.top,
                          szBuf,
                          lstrlen(szBuf));
    
                /* If enabled item has the input focus, call
                   DrawFocusRect to set or clear the focus
                   rectangle */ 
                if ((pDIS->itemState) & (ODS_FOCUS))
                   DrawFocusRect (PHDC, &PRC);
             }
    
             return TRUE; 


Strings that start with "!" are displayed dimmed. The exclamation mark character is not displayed.

Preventing Selection

To prevent a dimmed string from being selected, create the list box with the LBS_NOTIFY style. Then use the following code in the list box's parent window procedure to process the LBN_SELCHANGE notification:

   case WM_COMMAND:

    switch (wParam)
      {

       ...

      case IDD_LISTBOX:
        if (LBN_SELCHANGE == HIWORD(lParam))
          {
          idx = (int)SendDlgItemMessage(hDlg, wParam,
                        LB_GETCURSEL, 0, 0L);
          SendDlgItemMessage(hDlg, wParam, LB_GETTEXT, idx,
                        (LONG)(LPSTR)szBuf);
          if ('!' == *szBuf)
            {
            // Calculate an alternate index here
            // (not shown in this example).

            // Then set the index.
            SendDlgItemMessage(hDlg, wParam, LB_SETCURSEL, idx, 0L);
            }
          }
        break;

       ...

      }
  break; 

When the user attempts to select a dimmed item, the alternate index calculation moves the selection to an available item.

Additional query words: listbox WIN16SDK


Keywords          : kbCtrl kbListBox kbNTOS kbGrpUser kbWinOS 
Version           : 
Platform          : 
Issue type        : kbhowto 

Last Reviewed: March 7, 1999