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. The following are the most commonly used styles:

LBS_BORDER

The list box has a surrounding border.

LBS_NOTIFY

The list box sends notification messages to the parent window when the user selects an item.

LBS_SORT

The list box alphabetically sorts its items.

WS_VSCROLL

The list box has 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,

hInstance, NULL);

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.

Deleting a String from a List Box

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

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

You can also add a string to a list box is by sending the LB_INSERTSTRING message to the list box. Unlike LB_ADDSTRING, 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 with the LBS_SORT style.

Adding Filenames to a List Box

As noted earlier, a common use for a list box is to display a list of filenames, directories, and/or disk drives. 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 DOS attributes of the files, and the lParam parameter points to a string containing a file specification.

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 subdirectories and disk drives, you would send the LB_DIR message as shown 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 removing 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. The LB_GETCURSEL message retrieves the selection's index in the list box, and the LB_GETTEXT message retrieves the selection from the list box, copying it to a buffer that you supply.

The following list summarizes actions and results for the mouse and keyboard interface for a standard list box.

Mouse Interface

Single click

Selects the item and removes the selection from the previously selected item (if any).

Double click

Is the same as a single click.

Keyboard Interface

SPACEBAR

Selects the item.

RIGHT ARROW, DOWN ARROW

Selects the next item in the list and removes the selection from the previously selected item (if any).

LEFT ARROW, UP ARROW

Selects the preceding item in the list and removes the selection from the previously selected item (if any).

PGUP

Scrolls the currently selected item to the bottom of the list box, selects the first visible item in the list box, and removes the selection from the previously selected item (if any).

PGDN

Scrolls the currently selected item to the top of the list box, selects the last visible item in the list box, and removes the selection from the previously selected item (if any).

HOME

Scrolls the first item in the list box to the top of the list box, selects the first item, and removes the selection from the previously selected item (if any).

END

Scrolls the last item in the list box to the bottom of the list box, selects the last item, and removes the selection from the previously selected item (if any).

Using Multiple-Selection List Boxes

By default, a list box lets the user select only one item at a time. To allow the user to select more than one item from a list box, create the list box with either of the following styles:

LBS_MULTIPLESEL

A list box created with the LBS_MULTIPLESEL style is essentially the same as a standard list box, except that the user can select more than one item in the list box.

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.

The rest of this section describes each style of multiple-selection list box.

List Boxes with the LBS_MULTIPLESEL Style

A list box created with the LBS_MULTIPLESEL style is essentially the same as a standard list box, except that the user can select more than one item in the list box. Clicking or pressing the SPACEBAR on an item in the list box toggles the selection state of the item. If the user presses a character key while the list box has focus, the list-box cursor moves to the next item in the list that begins with that character; the item is not actually selected unless the user presses the SPACEBAR. The following list describes the actions and results for the mouse and keyboard interface for a list box with the LBS_MULTIPLESEL style.

Mouse Interface

Single click

Toggles the selection status of the item, but does not remove the selection from other selected items (if any).

Double click

Is the same as a single click.

Keyboard Interface

SPACEBAR

Toggles the selection status of the item, but does not remove the selection from other selected items (if any).

RIGHT ARROW, DOWN ARROW

Moves the list-box cursor to the next item in the list.

LEFT ARROW, UP ARROW

Moves the list-box cursor to the preceding item in the list.

PGUP

Scrolls the currently selected item to the bottom of the list box and moves the list-box cursor to the first visible item in the list box.

PGDN

Scrolls the currently selected item to the top of the list box and moves the list-box cursor to the last visible item in the list box.

HOME

Scrolls the first item in the list box to the top of the list box and moves the list-box cursor to the first item.

END

Scrolls the last item in the list box to the bottom of the list box and moves the list-box cursor to the last item.

List Boxes with the LBS_EXTENDEDSEL Style

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. The following list describes the actions and results for the mouse and keyboard interface for a list box with the LBS_EXTENDEDSEL style.

Mouse Interface

Single click

(Add mode disabled) Selects the item, removes the selection from other items, and drops the selection anchor on the selected item.

(Add mode enabled) Same as if add mode is disabled; in addition, disables add mode.

SHIFT+single click

(Add mode disabled) Selects all items between the selection anchor and the selected item, and removes the selection from items not in that range.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

Double click, SHIFT+double click

(Add mode disabled) Same as single click and SHIFT+single click.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

CTRL+single click

(Add mode disabled) Drops the selection anchor and toggles the selection state of the selected item, but does not remove the selection from other items.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

CTRL+SHIFT+single click

(Add mode disabled) Does not remove the selection from other items (except for those that are part of the selection range established by the most recent selection anchor) and toggles all items (to the same selection state as the item at the anchor point) from the anchor point to the selected item. Does not move the selection anchor.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

Drag

(Add mode disabled) Drops the selection anchor where the user pressed the mouse button, selects items from the selection anchor to the item where the the user released the button, and removes the selection from all other items.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

SHIFT+drag

(Add mode disabled) Selects items from the selection anchor to the item where the user released the button and removes the selection from all other items. Does not move the selection anchor.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

CTRL+drag

(Add mode disabled) Drops the selection anchor on the item where the user pressed the mouse button. Does not remove the selection from other items, but toggles all items (to the same selection state as the item at the anchor point) from the anchor point to the item where the user released the mouse button.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

CTRL+SHIFT+drag

(Add mode disabled) Does not remove the selection from other items (except for those that are part of the selection range established by the most recent selection anchor), but toggles all items (to the same selection state as the item at the anchor point) from the anchor point to the item where the user released the mouse button. Does not move the selection anchor.

(Add mode enabled) Same as if add mode is disabled, plus disables add mode.

Keyboard Interface (Except for SHIFT+F8, all keys and key combinations can be combined with CTRL. For example, CTRL+SHIFT+SPACEBAR has the same effect as SHIFT+SPACEBAR.)

SHIFT+F8

(Add mode disabled) Enables add mode. Add mode is indicated by a flashing list-box cursor.

(Add mode enabled) Disables add mode.

SPACEBAR

(Add mode disabled) Selects the item, removes the selection from previously selected items, and drops the selection anchor.

(Add mode enabled) Toggles the selection status of the item and drops the selection anchor, but does not remove the selection from other items.

SHIFT+SPACEBAR

(Add mode disabled) Removes the selection from previously selected items and toggles all items (to the same selection state as the item at the selection anchor) from the anchor point to the current position. Does not move the selection anchor.

(Add mode enabled) Does not remove the selection from other items (except for those that are part of the selection established by the most recent anchor point) and toggles all items (to the same selection state as the item at the selection anchor) from the selection anchor to the current position. Does not move the selection anchor.

Navigation key (Navigation keys include the ARROW keys and the HOME, END, PGUP, and PGDN keys. See “List Boxes with the LBS_MULTIPLESEL Style” for a description of how each key moves the list-box cursor.)

(Add mode disabled) Moves the list-box cursor as defined by the key and selects the item at the cursor, drops the selection anchor at the selected item, and removes the selection from all previously selected items.

(Add mode enabled) Moves the list-box cursor as defined by the key, but does not select the item, remove the selection from other items, or move the selection anchor.

SHIFT+Navigation key

(Add mode disabled) Removes the selection from all other items, moves the list-box cursor as defined by the key, toggles all items (to the same selection state as the item at the selection anchor) from the selection anchor to the item at the cursor. Does not move the selection anchor.

(Add mode enabled) Does not remove the selection from other items (except for those that are part of the selection range established by the most recent selection anchor), moves the list-box cursor as defined by the key, and toggles all items (to the same selection state as the item at the anchor point) from the anchor point to the item at the list-box cursor. Does not move the selection anchor.

Using Multicolumn List Boxes

Normally, 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 with the LBS_MULTICOLUMN style. This style specifies a list box that can display its items in several columns. A multicolumn list box “snakes” its items from the bottom of one column to the next. Because of this, the list box never needs to be scrolled vertically. However, if the list box may contain more items than it can display at one time, you should create it with the WM_HSCROLL style to allow the user to scroll the list box horizontally. 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 CreateWindow to set the location and size of the list box.

The directory window displayed by the Windows File Manager is an example of a window that contains a multicolumn list box.

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

Using Owner-Draw List Boxes

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

To create an owner-draw list box, use either the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style. LBS_OWNERDRAWFIXED designates an owner-draw list box in which all the items are the same height; LBS_OWNERDRAWVARIABLE specifies a list box whose items can vary in height.

To add an item to the list box, send the LB_ADDSTRING or LB_INSERTSTRING message to the list box. The 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 lets the list box 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 with the LBS_SORT and LBS_HASSTRINGS style, Windows automatically sorts the items in the list box.

If you create the list box with the LBS_SORT style but without LBS_HASSTRINGS, Windows has no way to 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 data structure containing identifying information for two items in the list box. When your application returns from processing the message, the return value specifies which, if any, of two items should appear above the other. Windows sends this message repeatedly until it has sorted all the items in the 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 needs 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, since all the items in the list box will be the same size. For a list box that was created with 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 data structure. In addition to the control type and ID, this data structure also contains the list-box item number of the item to be measured (if the list box is 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 field of the MEASUREITEMSTRUCT structure with the height of the item before returning from processing the message. The height is measured in vertical dialog units. A vertical dialog unit is 1/8 of the current vertical dialog base unit, which is computed from the height of the system font. To determine the size in pixels of the dialog base units, call the GetDialogBaseUnits function.

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 data structure. This structure contains information identifying the list box item and the type of drawing required. As with an owner-draw button, your application uses this information to determine how to draw the item.

To delete an item from an owner-draw list box, send the LB_DELETESTRING message to the list box. When this happens, Windows in turn sends the 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 data structure; this structure identifies the list box and 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 which was used for the item.