8.4.3 List Boxes

A list box is a box that contains a list of selectable items, such as filenames. You typically use a list box to display a list of items from which the user can select one or more. There are several styles associated with a list box. Following are the most common styles:

List box style Description

LBS_BORDER Specifies a surrounding border.
LBS_NOTIFY Sends notification messages to the parent window when the user selects an item.
LBS_SORT Sorts its items alphabetically.
WS_VSCROLL Specifies a vertical scroll bar.

These four styles are included in the LBS_STANDARD style. The following example creates a standard list box:

HWND hListBox
#define IDC_LISTBOX 203
   .
   .
   .

hListBox = CreateWindow("Listbox", NULL,
    LBS_STANDARD | WS_CHILD | WS_VISIBLE,
    20, 40, 120, 56, hWnd, IDC_LISTBOX,
    hinst, NULL);

8.4.3.1 Adding a String to a List Box

Use the LB_ADDSTRING message to add a string to a list box. This message copies the given string to the list box, which displays it in the list. If the list box has the LBS_SORT style, the string is sorted alphabetically. Otherwise, Windows simply places the string at the end of the list. The following example shows how to add a string:

int nIndex;
    .
    .
    .

nIndex = SendMessage(hListBox,
    LB_ADDSTRING, NULL,
    (LONG)(LPSTR) "Horseradish");

The LB_ADDSTRING message returns an integer that represents the index of the string in the list. You can use this index in subsequent list box messages to identify the string, but only as long as you do not add, delete, or insert any other string. Doing so may change the string's index.

You can also add a string to a list box by sending the LB_INSERTSTRING message to the list box. Unlike the LB_ADDSTRING message, LB_INSERTSTRING lets you specify where Windows should place the new string in the list box. When it receives the LB_INSERTSTRING message, the list box does not sort the list, even if the list box was created by using the LBS_SORT style.

8.4.3.2 Deleting a String from a List Box

You can delete a string from the list box by supplying the index of the string in the LB_DELETESTRING message, as in the following example:

SendMessage(hListBox, LB_DELETESTRING, nIndex, (LPSTR) NULL);

8.4.3.3 Adding Filenames to a List Box

As noted previously, a common use for a list box is to display a list of filenames, directories, or disk drives, or a combination of these. The LB_DIR message instructs the list box to fill itself with such a list. The message's wParam parameter contains a value specifying the MS-DOS attributes of the files, and the lParam parameter points to a string containing a valid filename template, which can include the question mark (?) or asterisk (*) wildcards.

For example, to fill a list box with the names of all files in the current directory that have the .TXT extension, plus a list of directories and disk drives, you would send the LB_DIR message, as in the following example:

#define FILE_LIST 4010;
    .
    .
    .

int nFiles;
    .
    .
    .

nFiles = SendMessage(hListBox, LB_DIR, FILE_LIST,
    (LPSTR) "*.TXT");

The return value of the LB_DIR message indicates how many items the list box contains.

Note:

If the list box is in a dialog box, you can call the DlgDirList function to perform the same task.

A list box responds to both mouse and keyboard input. If the user clicks a string or presses the SPACEBAR in the list box, the list box selects the string and indicates the selection by inverting the string text and canceling the selection from the last item that was selected, if any. The user can also press a character key to select an item in the list box; the next item in the list box that begins with the character is selected. If the list box has the LBS_NOTIFY style, the list box also sends an LBN_SELCHANGE notification message to the parent window. If the user double-clicks a string and LBS_NOTIFY is specified, the list box sends the LBN_SELCHANGE and LBN_DBLCLK messages to the parent window.

You can always retrieve the index of the selected string by using the LB_GETCURSEL and LB_GETTEXT messages. LB_GETCURSEL retrieves the selection's index in the list box, and LB_GETTEXT retrieves the selection from the list box, copying it to a buffer that you supply.

8.4.3.4 Using a Multiple-Selection List Box

A user can select only one list box item at a time, by default. To allow the user to select more than one item, create the list box by using either of the following styles:

Style Description

LBS_MULTIPLESEL A list box created with the LBS_MULTIPLESEL style is the same as a standard list box, except that the user can select more than one item in the list box.
  Pressing the SPACEBAR or clicking on an item in this style of list box changes the selection state of the item. If the user presses a character key while the list box has the focus, the selection moves to the next item that begins with that character; the item is not chosen unless the user presses the SPACEBAR.
LBS_EXTENDEDSEL A list box created with the LBS_EXTENDEDSEL style provides an easy method for selecting several contiguous items in the list box, as well as for selecting separate items.

8.4.3.5 Using a Multicolumn List Box

Usually, a list box displays its items in a single column. If you anticipate that a list box will contain a large number of items, you may want to create the list box by using the LBS_MULTICOLUMN style. This style specifies a list box that can display its items in several columns, “snaking” the items from the bottom of one column to the next. Because of this, the list box need not be scrolled vertically. However, if the list box may contain more items than it can display at one time, you should create it by using the WM_HSCROLL style to allow the user to scroll the list box horizontally.

The directory window that Windows File Manager displays is an example of a window that contains a multicolumn list box. The following example shows how to create a multicolumn list box that occupies the entire client area of the parent window:

#define IDC_MULTILISTBOX
RECT Rect;
HWND hMultiListBox
    .
    .
    .

GetClientRect(hWnd, (LPRECT) &Rect);

hMultiListBox = CreateWindow("Listbox",
    NULL,
    WS_CHILD | WS_VISIBLE | LBS_SORT |
    LBS_MULTICOLUMN | WS_HSCROLL | LBS_NOTIFY,
    Rect.left,
    Rect.top,
    Rect.right,
    Rect.bottom,
    hWnd,
    IDC_MULTILISTBOX,
    hinst,
    NULL);

In this example, the GetClientRect function retrieves the coordinates of the client area of the parent window, which are then passed to the CreateWindow function to set the location and size of the list box.

To set the width of the columns in a multicolumn list box, send the list box a LB_SETCOLUMNWIDTH message.

8.4.3.6 Using an Owner-Drawn List Box

Like a button, a list box can be created as an owner-drawn control. In the case of list boxes, however, your application is required to draw only the items in the list box.

Creating an Owner-Drawn List Box

To create an owner-drawn list box, use the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style. The LBS_OWNERDRAWFIXED style specifies an owner-drawn list box whose items are the same height; the style LBS_OWNERDRAWVARIABLE specifies a list box whose items can vary in height.

Adding an Item to an Owner-Drawn List Box

To add an item to the list box, send the list box the LB_ADDSTRING or LB_INSERTSTRING message. The message's lParam parameter can contain any 32-bit value that you want to associate with the item. If lParam contains a pointer to a string, the LBS_HASSTRINGS list box style allows the list box to maintain the memory and pointers for the string. This allows the application to use the LB_GETTEXT message to retrieve the text for the particular item. Also, if you created the list box by using the LBS_HASSTRINGS and the LBS_SORT styles, Windows automatically sorts the items in the list box.

If you create the list box by using the LBS_SORT style (and not the LBS_HASSTRINGS style), Windows cannot determine the order of the items within the list box. In this case, when you add an item to the list box (using the LB_ADDSTRING message), Windows will send one or more WM_COMPAREITEM messages to the owner of the list box. This message's lParam parameter points to a COMPAREITEMSTRUCT structure that contains identifying information for two items in the list box. When your application returns from processing the message, the return value specifies which of the items should appear above the other. Windows sends this message repeatedly until all the items in the list box are sorted.

Measuring an Item in an Owner-Drawn List Box

When you add or insert an item in a list box, Windows determines the size of the item by sending the WM_MEASUREITEM message to the owner of the list box. Windows requires this information so it can detect the user's interaction with items in the list box. If you created the list box with the LBS_OWNERDRAWFIXED style, Windows sends the message only once, because all the items in the list box will be the same size. For a list box that was created by using the LBS_OWNERDRAWVARIABLE style, Windows sends a WM_MEASUREITEM message for each item when that item is added to the list box.

The lParam parameter of WM_MEASUREITEM contains a pointer to a MEASUREITEMSTRUCT structure. In addition to the control type and identifier, this structure also contains the number of the list box item to be measured (if the list box is of the LBS_OWNERDRAWVARIABLE style) and optional 32-bit data associated with the item. Each time the owner window receives the WM_MEASUREITEM message, it must fill in the itemHeight member of MEASUREITEMSTRUCT with the height of the item before returning from processing the message.

Displaying or Updating an Item in an Owner-Drawn List Box

When Windows displays the list box, or whenever the appearance of an item in the list box should change, Windows sends the WM_DRAWITEM message to the window that owns the list box. The lParam parameter of the WM_DRAWITEM message contains a pointer to a DRAWITEMSTRUCT structure. This structure contains information identifying the list box item and the type of drawing required. As with an owner-drawn button, your application uses this information to determine how to draw the item.

Deleting an Item from an Owner-Drawn List Box

To delete an item from an owner-drawn list box, send the list box a LB_DELETESTRING message. Upon receiving this message, Windows sends a WM_DELETEITEM message to the owner window. (Windows also sends this message for each item when the list box is destroyed.) The lParam parameter of this message points to a DELETEITEMSTRUCT structure; this structure identifies the list box, the list box item that is being deleted, and the 32-bit optional data associated with the item. Your application should use this information to clean up any memory that was used for the item.