Nancy Winnick Cluts
Microsoft Developer Network Technology Group
April 1994
Revised: February 1995 (LVS_NOITEMDATA style deleted)
June 1995 (LVS_ALWAYSSEL removed; LVS_SHOWSELALWAYS added)
Click to open or copy the files in the ListView sample application for this technical article.
The next release of the Microsoft® Windows® operating system (called Windows 95) presents a new set of common controls to developers of Windows-based applications. These controls are provided in a new dynamic-link library (DLL) called COMCTL32.DLL. The controls allow developers to integrate existing applications into the new Windows 95 shell more thoroughly and seamlessly. COMCTL32.DLL is included with Windows 95 and will also be supported in Win32s® (running on Windows version 3.1) and in Windows NT™. Note that these controls are 32-bit only—they will not be supported in 16-bit Windows environments.
This article describes two new common controls, header windows and list view windows, which are generally used together. It is the fourth in a series of articles introducing the new common controls. The other articles in the series cover the following topics:
Parts 2–6 of the series have associated code samples that demonstrate the use of the Win32® common controls.
Warning The ListView executable file associated with this article was built and tested using the Windows 95 Preliminary Development Kit. The executable will run only on Windows 95; it will not run under Windows 3.1 or Windows NT. If you have Windows 95 installed on your machine, but you have problems running this sample, copy the project files to your system using the button above, rebuild the project, and run the executable.
Please note that this article is based on preliminary information that is subject to change before the final version of Windows 95.
A header window is a horizontal window usually positioned above columns of text or numbers, containing titles for each column. Microsoft® Mail and Microsoft Excel include examples of these controls. You can divide a header window into parts, called header items, and allow the user to set the width of each item. Items can behave like push buttons and do something (for example, sort data) when the user clicks them. Header items appear as text on a gray background. It is important to note that header windows do not support a keyboard interface, and, as a result, do not accept the input focus.
Header windows are generally used in conjunction with list view windows. You can see an example of a header window/list view window combination in the ListView sample that is associated with this article.
Each item in a header window can have a string, a bitmapped image, and an application-defined 32-bit value associated with it. The string and bitmap are displayed within the boundaries of the item. If an item contains both a string and an image, the image is displayed above the string. If the string and image overlap, the string overwrites the overlapping portion of the image. Figure 1 illustrates a typical header window with four header items.
Figure 1. A header window with four header items
Header windows can have different window styles that determine the appearance and behavior of the window. For example, if you include the HDS_DIVIDERTRACK window style, the user will be able to set the width of the items by dragging the divider between the items with the mouse. You set the initial styles when you create the header window. If you want to get the current styles or change the styles later, you can use the GetWindowLong and SetWindowLong functions. Table 1 lists the header window styles supported in the Microsoft Windows® 95 operating system.
Table 1. Header Window Styles
Style | Use |
HDS_BUTTONS | Causes header items to act like push buttons. This style is useful if your application must do something (for example, sort a list) when the user clicks a header item. |
HDS_DIVIDERTRACK | Enables the user to use the divider area between header items to set the width of the items. |
HDS_HIDDEN | Hides the header window. (You may want to do this, for example, if you want to create the header window when launching your application, but fill in the text for header items later, or if you want to reuse the header window and dynamically change the associated text.) |
HDS_HORZ | Specifies a horizontal header window. |
Typically, you must set the size and position of a header window to fit within the boundaries of a particular rectangle, such as the client area of the parent window. The default position is (–100, –100); the default width and height are 10 device units each. You can query the system for the appropriate size and position by sending the HDM_LAYOUT message to the header window. When sending this message, you fill in the coordinates of the rectangle that the header window should occupy, and you pass a pointer to a WINDOWPOS structure. The header window fills in the WINDOWPOS structure with size and position values appropriate for positioning the window along the top of the specified rectangle. The height value is the sum of the width of the window's horizontal borders and the average height of characters in the font currently selected into the window's device context. If you want to use the HDM_LAYOUT message to set the initial size and position of a header window, you should set the initial visibility state of the window so that it is hidden (by specifying the HDS_HIDDEN style). Once you have created the window and used the HDM_LAYOUT message to get the size and position values, you can call the SetWindowPos function to set the new size, position, and visibility state.
You can create a header window by calling the CreateWindow or CreateWindowEx function, and specifying WC_HEADER for the class name. You can use the following code to create a header window and position it along the top of its parent window's client area. The code uses the Header_Layout macro (which sends the HDM_LAYOUT message) to get the appropriate size and position for the header window, given the bounding rectangle of the parent window's client area. The CreateHeaderWindow function returns the handle of the newly created header window. If the header window cannot be created, the function returns NULL.
HWND CreateHeaderWindow(HWND hwndParent)
{
HWND hwndHeader;
RECT rcParent;
HD_LAYOUT hdl;
WINDOWPOS wp;
if ((hwndHeader = CreateWindowEx(
0L, // No extended styles.
WC_HEADER, // A header class window.
(LPCTSTR) NULL, // No default text.
WS_CHILD | WS_BORDER | HDS_BUTTONS | HDS_HORZ | HDS_DIVIDERTRACK,
0, 0, 0, 0, // No size or position.
hwndParent, // Handle to the parent window.
(HMENU) ID_HEADER, // ID for the header window.
hInst, // Current instance.
(LPVOID) NULL)) == NULL) // No application-defined data.
return (HWND) NULL;
// Get the bounding rectangle of the parent window's client area.
GetClientRect(hwndParent, &rcParent);
hdl.prc = &rcParent;
hdl.pwpos = ℘
// Call the Header_Layout macro to get the appropriate size
// for the window.
if (Header_Layout (hwndHeader, &hdl) == FALSE)
return (HWND) NULL;
// Set the size, position, and visibility of the header window.
SetWindowPos(hwndHeader, wp.hwndInsertAfter, wp.x, wp.y,
wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW);
return hwndHeader;
}
Now that the header window has been created, it is time to start adding items to it. (It would be pretty silly to have a header window with no items.) You can add an item to a header window by sending the HDM_INSERTITEM message to the window or by calling the Header_InsertItem macro. The HDM_INSERTITEM message includes the address of an HD_ITEM structure that defines the properties of the item, including its string, bitmap, initial size, and application-defined value. The structure also specifies formatting flags that tell the header window whether to center, left-justify, or right-justify the string or bitmap within the item's rectangle. The following code demonstrates how to add an item (string or bitmap) to a header window using the Header_InsertItem macro.
BOOL InsertItem(HWND hwndHeader, LPSTR lpsz, HBITMAP hBitmap)
{
HD_ITEM hdi; // Header item.
// The .fmt member is valid and the .cxy member specifies the width.
hdi.mask = HDI_FORMAT | HDI_WIDTH;
hdi.fmt = HDF_LEFT; // Left-justify the item.
if (lpsz) // It is a string.
{
hdi.mask |= HDI_TEXT; // The .pszText member is valid.
hdi.pszText = lpsz; // The text for the item.
hdi.cxy = 75; // The initial width.
hdi.cchTextMax = lstrlen(hdi.pszText); // The length of the string.
hdi.fmt |= HDF_STRING; // This item is a string.
}
if (hBitmap)
{
hdi.mask |= HDI_BITMAP; // The .hbm member is valid.
hdi.cxy = 32; // The initial width.
hdi.hbm = hBitmap; // The handle to the bitmap.
hdi.fmt |= HDF_BITMAP; // This item is a bitmap.
}
// Insert the item at the current index.
if (Header_InsertItem(hwndHeader, CurrIndex, &hdi) == TRUE)
{
CurrIndex++; // Increment the index.
return TRUE;
}
return FALSE;
}
An application sends messages to header windows as it would to any other window, to change the behavior and appearance of the window. For example, you can add items, delete items, or change the text of an item by sending the appropriate message. Each message has a corresponding macro that you can send to a header window. This section lists header window messages, the corresponding macros, return values, and parameters. The hwndHD parameter for each macro is the handle to the header window. In many cases, wParam and lParam are zero and not used. The structures mentioned in the descriptions below are described in the next section, "Header Window Structures."
wParam = i; \\ index of the item to delete
lParam = 0; \\ not used
Description: The HDM_DELETEITEM message deletes an item from a header window.
Parameters: wParam (int i) is the index of the item to delete. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: BOOL Header_DeleteItem(hwndHD, i);
wParam = i; \\ index of the item
lParam = (HD_ITEM *)phdi; \\ buffer receiving the item information
Description: The HDM_GETITEM message gets information about an item in a header window.
Parameters: wParam (int i) is the index of the item for which information is requested. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure. The mask member of the HD_ITEM structure indicates the type of information being requested. The other members of the structure are filled in based on the requested information. If mask is zero, the message returns TRUE, but copies no information to the HD_ITEM structure.
Return value: TRUE if successful; FALSE otherwise.
Macro: BOOL Header_GetItem(hwndHD, i, phdi);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The HDM_GETITEMCOUNT message gets a count of the items in a header window.
Parameters: wParam and lParam are not used.
Return value: The number of items if successful; –1 otherwise.
Macro: int Header_GetItemCount(hwndHD);
wParam = i; \\ index of the item after which to insert
lParam = (HD_ITEM *)phdi; \\ structure containing item information
Description: The HDM_INSERTITEM message inserts a new item within a header window.
Parameters: wParam (int i) is the index of the item after which the new item is to be inserted. The new item is inserted at the end of the header window if i is greater than or equal to the number of items in the window. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure that contains information about the new item.
Return value: The index of the new item if successful; –1 otherwise.
Macro: int Header_InsertItem(hwndHD, i, phdi);
wParam = 0; \\ not used
lParam = (HD_LAYOUT *)playout; \\ structure containing layout information
Description: The HDM_LAYOUT message gets the size and position of a header within a given rectangle. This message is used to determine the dimensions of a new header window, given the bounding rectangle specified in the prc member of the HD_LAYOUT structure.
Parameters: wParam is not used. lParam (HD_LAYOUT * playout) is the address of an HD_LAYOUT structure. In HD_LAYOUT, the prc member specifies the coordinates of a rectangle, and the pwpos member is filled in with the size and position of the header window within the given rectangle.
Return value: TRUE if successful; FALSE otherwise.
Macro: BOOL Header_Layout(hwndHD, playout);
wParam = i; \\ index of the item to be set
lParam = (HD_ITEM *)phdi; \\ structure containing item information
Description: The HDM_SETITEM message sets the attributes of the specified item in a header window. The HDN_ITEMCHANGING notification is sent to the parent window before the item attributes are changed. The parent window can return FALSE to prevent the changes, in which case HDM_SETITEM returns FALSE. If the parent window returns TRUE, the changes are made and the parent window receives an HDN_ITEMCHANGED notification.
Parameters: wParam (int i) is the index of the item whose attributes are to be changed. lParam (HD_ITEM * phdi) is the address of an HD_ITEM structure. The mask member of the HD_ITEM structure indicates the attributes to set. The other members of the structure specify the new attributes.
Return value: TRUE if successful; FALSE otherwise.
Macro: BOOL Header_SetItem(hwndHD, i, phdi);
This section lists the new structures in Windows 95 that support header windows. An application may need to use these structures whenever it sends a message or notification to a header window.
typedef struct _HD_ITEM {
UINT mask; \\ mask flags, as described below
int cxy; \\ width and height of the item
LPSTR pszText; \\ the item string
HBITMAP hbm; \\ handle of the item bitmap
int cchText; \\ length of the item string, in characters
int fmt; \\ format flags, as described below
LPARAM lParam; \\ application-defined data
} HD_ITEM;
The HD_ITEM structure contains information about an item in a header window. You fill in this structure whenever you add an item to the header window. You can also get this information by using the Header_GetItem macro. The HD_ITEM structure has the following members:
HDI_BITMAP: The hbm member is valid.
HDI_FORMAT: The fmt member is valid.
HDI_HEIGHT: The cxy member is valid and specifies the height of the item.
HDI_LPARAM: The lParam member is valid.
HDI_TEXT: The pszText and cchTextMax members are valid.
HDI_WIDTH: The cxy member is valid and specifies the width of the item.
HDF_CENTER: Center the contents (string or bitmap) of the item.
HDF_LEFT: Left-justify the contents of the item.
HDF_RIGHT: Right-justify the contents of the item.
This member can also be combined with one of the following values:
HDF_BITMAP: The item displays a bitmap.
HDF_OWNERDRAW: The header window's parent window draws the item.
HDF_STRING: The item displays a string.
typedef struct _HD_LAYOUT {
RECT FAR *prc; \\ bounding rectangle coordinates
WINDOWPOS FAR *pwpos; \\ appropriate size for the header window
} HD_LAYOUT;
The HD_LAYOUT structure contains information for setting the size and position of a header window. This structure is used with the HDM_LAYOUT message and contains the following members:
typedef struct _HD_NOTIFY {
NMHDR hdr; \\ common control notification structure
int iItem; \\ index of the item
int iButton; \\ index of the mouse button
HD_ITEM *pitem; \\ item information
} HD_NOTIFY;
The HD_NOTIFY structure contains information used to process notification messages from a header window. This structure contains the following members:
0: The user clicked the left mouse button.
1: The user clicked the right mouse button.
2: The user clicked the middle mouse button.
Table 2 lists the notification messages that Windows sends to header windows. The parent window of the header window receives these messages via a WM_NOTIFY message. For each notification, the lParam is a FAR pointer to an HD_NOTIFY structure (described in the previous section).
Table 2. Header Window Notification Messages
Message | Description |
HDN_BEGINTRACK | Sent when the user begins dragging a divider in the window (the user has pressed the left mouse button while the mouse cursor is over a divider in the header window). The parent window may return FALSE to allow tracking of the divider, or TRUE to prevent tracking. |
HDN_ENDTRACK | Sent when the user finishes dragging a divider. |
HDN_ITEMCHANGED | Sent when the attributes of a header item have changed. |
HDN_ITEMCHANGING | Sent when the attributes of a header item are about to change. The parent window may return FALSE to allow the changes, or TRUE to prevent them. |
HDN_ITEMCLICK | Sent when the user clicks the header window. A header window sends this notification after the user releases the left mouse button. A window that has the HDS_DIVIDERTRACK style does not send this notification when the user clicks the divider. |
HDN_TRACK | Sent when the user drags a divider in the header window. The parent window may return FALSE to continue tracking the divider, or TRUE to end tracking. |
A list view window displays a collection of items such as files or folders. The user or an application can manipulate these items in a variety of ways, for example, they can drag the items or sort them by clicking the column headings. Any number of subitems can be associated with each item, but all items must have the same number of subitems. A subitem contains a text string that appears next to the item in report view.
A list view window can be viewed in four different ways (views): using their large (or standard) icons, using their small icons, as a list, or as a report. The current view is specified by two window style bits that you can set with the SetWindowStyle function.
In standard icon view, each item is represented by a full-sized icon and a text label. The user can drag items to any location in the list view window. A list view window in standard icon view (illustrated in Figure 2) resembles a program group in the Windows 3.1 Program Manager.
Figure 2. A list view window in standard icon view
In small icon view, each item is represented by a small icon and text to the right of the icon, thus saving screen real estate. As in standard icon view, the user can drag the items to any location in the window. Figure 3 shows a list view window in small icon view. To avoid truncating the labels, you can reset the length of the displayed text in your program.
Figure 3. A list view window in small icon view
List view also uses the small icon and the text label to the right of the icon, but the items are arranged in columns and cannot be dragged by the user (Figure 4).
Figure 4. A list view window in list view
In report view, you can display the items with their small icons and labels, and you can provide additional information about each item. Each item appears on its own line, with information arranged in columns. The leftmost column contains the icon, followed by the text label. Additional columns display the text for each of the item's subitems. Optionally, you can use a header window to show the title of each column. In Figure 5, if the user clicks one of the column headings, the list is sorted based on the sort criterion specified for that column. For example, clicking the Bedrooms heading sorts the data by the number of bedrooms.
Figure 5. A list view window in report view
You can specify different window styles when you create a list view window to determine the appearance and behavior of the window. You set the initial styles when you create the list view window with the CreateWindow or CreateWindowEx function. Table 3 lists the window styles that Windows 95 supports for list view windows.
Table 3. List View Window Styles
Style | Use |
LVS_ICON, LVS_SMALLICON, LVS_LIST, or LVS_REPORT |
Specifies the current view for the window: standard icon, small icon, list, or report. |
LVS_SINGLESEL | Allows the user to select only one item at a time from the list view window. By default, the user may select multiple items. |
LVS_SHOWSELALWAYS | Specifies that the selection (if any) should always be shown, even if the list view does not have the focus. |
LVS_SORTASCENDING or LVS_SORTDESCENDING | Sorts items based on their text labels. Items can be sorted either in ascending or descending order. |
LVS_SHAREIMAGELISTS | Prevents image lists from being created when the window is created, or destroyed when the window is destroyed. |
LVS_NOLABELWRAP | Displays text labels on a single line in icon view. By default, text labels may wrap in icon view. |
LVS_AUTOARRANGE | Automatically arranges icons in standard icon view and small icon view. |
LVS_EDITLABELS | Allows the user to edit text labels in place. |
LVS_ALIGNLEFT, LVS_ALIGNRIGHT, LVS_ALIGNBOTTOM, or LVS_ALIGNTOP | Specifies the alignment of items within the list view window. These flags only apply to standard icon and small icon view. |
LVS_NOCOLUMNHEADER | Specifies that there is no column header. This style is valid for report view only. |
LVS_NOSCROLL | Disables scrolling. No item is allowed outside of the client area. |
LVS_STATEIMAGES | Indicates that there is a user-defined state for the images. This style uses the state image list. |
Use the SetWindowStyle function to set some or all of the window styles for a list view window, and to notify the list view window that its style is changing. This function sends the WM_STYLECHANGING and WM_STYLECHANGED messages to the list view window. The mask parameter of SetWindowStyle can be one of the following:
Each item in a list view window has a current state (for example, selected or marked). These states are updated in response to a user's actions or when they are changed explicitly in the code. By default, the list view window maintains the state of each list item. However, you can specify that the list view notify the parent window (using the LVN_GETDISPINFO notification) whenever it needs to determine the state of an item via a callback. Table 4 lists the different states allowed for items.
Table 4. List View Item States
Value | Meaning |
LVIS_SELECTED | The item is selected. The appearance of a selected item depends on whether it has the focus and on the system colors used for selection. |
LVIS_FOCUSED | The item has the focus and is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus. |
LVIS_CUT | The item is checked. |
LVIS_DISABLED | The item is disabled and is drawn using the standard disabled style and coloring. |
LVIS_HIDDEN | The item is not visible and does not respond to user interaction. |
LVIS_DROPHILITED | The item is highlighted as a drag-and-drop target. |
LVIS_LINK | The item is a link and is drawn accordingly. |
LIVS_OVERLAYMASK | The item is used as an image list overlay image. |
LVIS_USERMASK | The item uses client bits for state image drawing. |
Creating a list view window may appear to be a daunting task at first. Getting all of the information placed in the correct structures involves several steps:
The following code demonstrates these steps. For my sample, I created a real-estate listing. A structure that I defined contains information about the houses listed, including address, city, price, number of bedrooms, and number of bathrooms. I created an icon for each city represented (three icons total).
// House structure used for listing.
typedef struct tagHOUSEINFO {
char szAddress[MAX_ADDRESS];
char szCity[MAX_CITY];
int iPrice;
int iBeds;
int iBaths;
} HOUSEINFO;
// Function that creates the list view window.
HWND CreateListView (HWND hWndParent)
{
HWND hWndList; // Handle to the list view window.
RECT rcl; // Rectangle for setting the size of the window.
HICON hIcon; // Handle to an icon.
int index; // Index used in for loops.
HIMAGELIST hSmall, hLarge; // Handles to image lists for large and small
// icons.
LV_COLUMN lvC; // List view column structure.
char szText[64]; // place to store some text.
LV_ITEM lvI; // List view item structure.
int iSubItem; // Index for inserting subitems.
// Ensure that the common window DLL is loaded.
InitCommonControls();
// Get the size and position of the parent window.
GetClientRect(hWndParent, &rcl);
// Create the list view window.
hWndList = CreateWindowEx( 0L,
WC_LISTVIEW, // List view class.
"", // No default text.
WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT, // Window styles.
0, 0, // Default x and y position.
rcl.right - rcl.left, rcl.bottom - rcl.top, // Width and height of window.
HWndParent, // Parent window.
(HMENU) ID_LISTVIEW, // Window ID.
HInst, // Current instance.
NULL ); // No application-defined data.
if (hWndList == NULL )
return NULL;
// Initialize the list view window.
// First, initialize the image lists we will need
// to create an image list for the small icons.
hSmall = ImageList_Create ( BITMAP_WIDTH, BITMAP_HEIGHT, FALSE, 3, 0 );
// Create an image list for the large icons.
hLarge = ImageList_Create (BITMAP_WIDTH, BITMAP_HEIGHT, FALSE, 3, 0 )
// Load the icons and add them to the image lists.
for (index = REDMOND; index <= SEATTLE ; index++)
{
hIcon = LoadIcon ( hInst, MAKEINTRESOURCE(index));
// There are 3 of each icon type, so add 3 at a time.
for (iSubItem = 0; iSubItem < 3; iSubItem++)
{
if ((ImageList_AddIcon(hSmall, hIcon) == -1) ||
(ImageList_AddIcon(hLarge, hIcon) == -1))
return NULL;
}
}
// Make sure that all of the icons are in the lists.
if (ImageList_GetImageCount(hSmall) < 3)
return FALSE;
if (ImageList_GetImageCount(hLarge) < 3)
return FALSE;
// Associate lists with list view window.
ListView_SetImageList(hWndList, hSmall, LVSIL_SMALL);
ListView_SetImageList(hWndList, hLarge, LVS1L_NORMAL);
// Now initialize the columns we will need.
// Initialize the LV_COLUMN structure.
// The mask specifies that the .fmt, .ex, width, and .subitem members
// of the structure are valid.
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvC.fmt = LVCFMT_LEFT; // Left-align the column.
lvC.cx = 75; // Width of the column, in pixels.
lvC.pszText = szText; // The text for the column.
// Add the columns. They are loaded from a string table.
for (index = 0; index <= NUM_COLUMNS; index++)
{
lvC.iSubItem = index;
LoadString( hInst,
IDS_ADDRESS + index,
szText,
sizeof(szText));
if (ListView_InsertColumn(hWndList, index, &lvC) == -1)
return NULL;
}
// Finally, let's add the actual items to the window.
// Fill in the LV_ITEM structure for each of the items to add
// to the list.
// The mask specifies that the .pszText, .iImage, .lParam and .state
// members of the LV_ITEM structure are valid.
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvI.state = 0;
lvI.stateMask = 0;
for (index = 0; index < NUM_ITEMS; index++)
{
lvI.iItem = index;
lvI.iSubItem = 0;
// The parent window is responsible for storing the text. The list view
// window will send an LVN_GETDISPINFO when it needs the text to display.
lvI.pszText = LPSTR_TEXTCALLBACK;
lvI.cchTextMax = MAX_ITEMLEN;
lvI.iImage = index;
lvI.lParam = (LPARAM)&rgHouseInfo[index];
if (ListView_InsertItem(hWndList, &lvI) == -1)
return NULL;
for (iSubItem = 1; iSubItem < NUM_COLUMNS; iSubItem++)
{
ListView_SetItemText( hWndList,
index,
iSubItem,
LPSTR_TEXTCALLBACK);
}
}
return (hWndList);
}
To see how the code above behaves, click to open the ListView project files and run LISTVIEW.EXE.
Warning The ListView executable file was built and tested using the Windows 95 Preliminary Development Kit. The executable will run only on Windows 95; it will not run under Windows 3.1 or Windows NT. If you have Windows 95 installed on your computer but you have problems running this sample, copy the project files to your system, rebuild the project, and run the executable.
Once you have created a list view window, you need some way to handle the WM_NOTIFY messages that will be sent to the parent window. The following code is an implementation of a handler that I set up to do this. When the parent window receives the WM_NOTIFY notification, it calls this function to see whether it needs text for a list view item and whether it is necessary to sort the items. I am only interested in two of the notifications: the LVN_GETDISPINFO notification, which is sent when the system needs text supplied for a list view item, and the LVN_COLUMNCLICK notification, which is sent whenever the user clicks a column heading.
LRESULT NotifyHandler( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;
NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;
HOUSEINFO *pHouse = (HOUSEINFO *)(pLvdi->item.lParam);
static char szText[10];
if (wParam != ID_LISTVIEW)
return 0L;
switch(pLvdi->hdr.code)
{
case LVN_GETDISPINFO:
// Display the appropriate item, getting the text or number
// from the HOUSEINFO structure I set up.
switch (pLvdi->item.iSubItem)
{
case 0: // Address
pLvdi->item.pszText = pHouse->szAddress;
break;
case 1: // City
pLvdi->item.pszText = pHouse->szCity;
break;
case 2: // Price
wsprintf(szText, "$%u", pHouse->iPrice);
pLvdi->item.pszText = szText;
break;
case 3: // Number of bedrooms
wsprintf(szText, "%u", pHouse->iBeds);
pLvdi->item.pszText = szText;
break;
case 4: // Number of bathrooms
wsprintf(szText, "%u", pHouse->iBaths);
pLvdi->item.pszText = szText;
break;
default:
break;
}
break;
case LVN_COLUMNCLICK:
// The user clicked one of the column headings. Sort by
// this column. This function calls an application-defined
// comparison callback function, ListViewCompareProc. The
// code for the comparison procedure is listed in the next section.
ListView_SortItems( pNm->hdr.hwndFrom,
ListViewCompareProc,
(LPARAM)(pNm->iSubItem));
break;
default:
break;
}
return 0L;
}
Our list view window is now almost fully functional. The only thing left to implement is the code to sort the list view items when the user clicks a column heading. The list view window does not sort the items for you. (Drats!) This makes some sense—how would the system know which criterion you wanted to sort on (for example, color or size)? However, I would have liked to see Windows 95 provide some built-in sorting callbacks for "standard" sorting needs such as string comparisons and numeric sorts. (I guess I'll have to drop another suggestion in the big black box.) Because the list view window doesn't have this capability, you have to provide a callback function to do the sorting.
The following code demonstrates one method of sorting. It uses the lstrcmpi function to compare strings and simple arithmetic to sort the numbers. The lstrcmpi function compares two strings by checking the first character in the strings, the second character, the third character, and so on against each other until it reaches the end of the strings or it finds an inequality. The function returns the difference of the values of the first mismatched characters it encounters, for example, it determines that "abcz" is greater than "abcdefg" and returns the difference between z and d. For those of you who have localization concerns, the language (locale) selected by the user at setup time (or via the Control Panel) determines which string is greater (or whether the strings are the same). If no language (locale) is selected, Windows performs the comparison by using default values. This function can compare two double-byte character set (DBCS) strings in the DBCS version of Windows:
int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM
lParamSort)
{
HOUSEINFO *pHouse1 = (HOUSEINFO *)lParam1;
HOUSEINFO *pHouse2 = (HOUSEINFO *)lParam2;
LPSTR lpStr1, lpStr2;
int iResult;
if (pHouse1 && pHouse2)
{
switch( lParamSort)
{
case 0: // Sort by address.
lpStr1 = pHouse1->szAddress;
lpStr2 = pHouse2->szAddress;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case 1: // Sort by city.
lpStr1 = pHouse1->szCity;
lpStr2 = pHouse2->szCity;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case 2: // Sort by price.
iResult = pHouse1->iPrice - pHouse2->iPrice;
break;
case 3: // Sort by the number of bedrooms.
iResult = pHouse1->iBeds - pHouse2->iBeds;
break;
case 4: // Sort by the number of bathrooms.
iResult = pHouse1->iBaths - pHouse2->iBaths;
break;
default:
iResult = 0;
break;
}
}
return(iResult);
}
This very long section lists the new messages you can use to manipulate list view windows. My suggestion is to skip to the next section, "List View Structures," and refer back to this section when you want to learn about specific functionality. Of course, if you love reading lists, this will be your favorite section. For the messages listed below, HWND hwndLV refers to the handle to the list view window unless otherwise noted. In many cases, wParam and/or lParam are zero and not used.
wParam = UINT code; \\ alignment and sort flag
lParam = 0; \\ not used
Description: The LVM_ARRANGE message arranges the items in icon view.
Parameters: wParam (UINT code) is the alignment and (optionally) the sort flag. The sort flag can be one of the values listed in Table 5 below. lParam is not used.
Table 5. List View Alignment Options
Value | Meaning |
LVA_DEFAULT | Use the current alignment. |
LVA_ALIGNLEFT | Align along the left of the list window. |
LVA_ALIGNTOP | Align along the top of the list window. |
LVA_ALIGNBOTTOM | Align along the bottom of the list window. |
LVA_ALIGNRIGHT | Align along the right of the list window. |
LVA_SNAPTOGRID | Arrange the icons according to the closest grid position. |
LVA_SORTASCENDING | Sort in ascending order. |
LVA_SORTDESCENDING | Sort in descending order. |
Return value: TRUE if successful; FALSE otherwise.
Macro: BOOL ListView_Arrange(HWND hwndLV, UINT code);
wParam = i; \\ index of the list view item
lParam = lpptUpLeft; \\ not used
Description: The LVM_CREATEDRAGIMAGE message creates a drag image for the specified item.
Parameters: wParam (int i) is the index of the list view item. lParam (LPPOINT lpptUpLeft) is the address of a POINT structure that receives the initial location of the upper-left corner of the image, in view coordinates.
Return value: The handle to the image list created, or NULL if unsuccessful.
Macro: (HIMAGELIST)ListView_CreateDragImage(hwndLV, iItem, lpptUpLeft);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_DELETEALLITEMS message removes all items from a list view window.
Parameters: wParam and lParam are not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_DeleteAllItems(hwndLV);
wParam = iCol; \\ index of the column to delete
lParam = 0; \\ not used
Description: The LVM_DELETECOLUMN message removes a column from a list view window.
Parameters: wParam (int iCol) is the index of the column to delete. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_DeleteColumn(hwndLV, iCol);
wParam = i; \\ index of the item to delete
lParam = 0; \\ not used
Description: The LVM_DELETEITEM message removes an item from a list view window.
Parameters: wParam (int i) is the index of the item to delete. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_DeleteItem(hwndLV, i);
wParam = i; \\ index of the item being edited
lParam = 0; \\ not used
Description: The LVM_EDITLABEL message begins in-place editing of an item's text. This message selects and sets the focus to the item. When the user completes or cancels editing, the edit window is destroyed and the handle becomes invalid. You can safely subclass the edit window, but do not destroy it. To cancel editing, you can send the list view a WM_CANCELMODE message.
Parameters: wParam (int i) is the index of the list view item being edited. lParam is not used.
Return value: If successful, the message returns the handle of the edit window used to edit the text. This will be NULL if the editing is unsuccessful.
Macro: (HWND)ListView_EditLabel(hwndLV, i);
wParam = i; \\ index of the item
lParam = (BOOL)fPartialOK; \\ TRUE to prohibit scrolling
Description: The LVM_ENSUREVISIBLE message ensures that a list view item is entirely or partially visible by scrolling the list view window if necessary.
Parameters: wParam (int i) is the index of the list view item. If lParam (BOOL fPartialOK) is TRUE, no scrolling will occur if the item is at least partially visible. If FALSE, the item must be entirely visible.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_EnsureVisible(hwndLV, I, fPartialOK);
wParam = iStart; \\ index of item to start search
lParam = (LV_FINDINFO *)plvfi; \\ structure specifying search criteria
Description: The LVM_FINDITEM message searches for a list view item.
Parameters: wParam (int iStart) is the index of the item at which the search will start. Specifying –1 will start the search at the beginning. lParam (LV_FINDINFO *plvfi) is the structure that specifies the search criteria.
Return value: If successful, the message returns an int indicating the index of the list view item. If unsuccessful, the message returns –1.
Macro: (int)ListView_FindItem(hwndLV, iStart, plvfi);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETBKCOLOR message gets the background color of the list view window.
Parameters: wParam and lParam are not used.
Return value: The background color of the window (COLORREF).
Macro: (COLORREF) ListView_GetBkColor (hwndLV);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETCALLBACKMASK message gets the callback mask for a list view window. For information about the callback mask, see Table 4, List View Item States, previously in this article.
Parameters: wParam and lParam are not used.
Return value: The callback mask (UINT).
Macro: (UINT)ListView_GetCallbackMask(hwndLV);
wParam = iCol; \\ index of the column
lParam = (LV_COLUMN FAR *)pcol; \\ structure that gets the column information
Description: The LVM_GETCOLUMN message gets the attributes of a list view column. The mask member of the LV_COLUMN structure passed in specifies which attributes to get. If the LVCF_TEXT flag is specified, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer.
Parameters: wParam (int iCol) is the index of the column. lParam (LV_COLUMN FAR * pcol) is the structure to be filled in with column information.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetColumn(hwndLV, iCol, pcol);
wParam = iCol; \\ index of the column
lParam = 0; \\ not used
Description: The LVM_GETCOLUMNWIDTH message gets the width of a column in list view or report view.
Parameters: wParam (int iCol) is the index of the column. This is ignored in list view. lParam is not used.
Return value: The column width if successful; zero otherwise.
Macro: (int)ListView_GetColumnWidth(hwndLV, iCol);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETCOUNTPERPAGE message calculates the number of items that can fit vertically in the visible area of a view control in list view or report view.
Parameters: wParam and lParam are not used.
Return value: The number of items if successful. If the list view is currently in standard icon or small icon view, the return value is the total number of items in the list view.
Macro: (int)ListView_GetCountPerPage(hwndLV);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETEDITCONTROL message gets the handle of the edit window used to edit the item text in place. The edit window is destroyed and the handle becomes invalid when the user completes or cancels editing. You can safely subclass the edit window, but do not destroy it. To cancel editing, you can send the list view a WM_CANCELMODE message. The list view item being edited is the item that is currently in the focused state.
Parameters: wParam and lParam are not used.
Return value: The handle of the edit window if successful. If the message is unsuccessful or no label is currently being edited, the message returns NULL.
Macro: (HWND)ListView_GetEditControl(hwndLV);
wParam = (BOOL)fSmallImages; \\ TRUE to get small icon list
lParam = 0; \\ not used
Description: The LVM_GETIMAGELIST message gets the handle of an image list used for drawing list view items.
Parameters: If wParam (int fSmallImages) is TRUE, the message returns a handle for the small icon image list; if FALSE, the message returns a handle for the standard icon image list. lParam is not used.
Return value: The handle of the specified image list if successful; NULL otherwise.
Macro: HIMAGELIST ListView_GetImageList(hwndLV, fSmallImages);
wParam = 0; \\ not used
lParam = (LV_ITEM FAR *)pitem; \\ structure receiving item information
Description: The LVM_GETITEM message gets a list view item's attributes.
Parameters: wParam is not used. lParam (LV_ITEM FAR * pitem) is the item structure to fill in. The iItem and iSubItem members of the LV_ITEM structure identify the item or subitem on which to get information, and the mask member specifies the attributes to get. If the mask member specifies the LVIF_TEXT flag, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer. If the mask member specifies the LVIF_STATE flag, the stateMask member specifies which item states are to be returned.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetItem(hwndLV, pitem);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETITEMCOUNT message gets the number of items in a list view window.
Parameters: wParam and lParam are not used.
Return value: The number of items.
Macro: (int)ListView_GetItemCount(hwndLV);
wParam = i; \\ index of the list view item
lParam = (POINT FAR *)ppt; \\ position of the item
Description: The LVM_GETITEMPOSITION message gets the position of a list view item in standard icon and small icon views.
Parameters: wParam (int i) is the index of the list view item. lParam (POINT FAR* ppt) is the position of the item in the list view window's client coordinates.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetItemPosition(hwndLV, I, ppt);
wParam = i; \\ index of the item
lParam = (RECT FAR *)prc; \\ bounding rectangle
Description: The LVM_GETITEMRECT message gets the bounding rectangle for an item in the current view.
Parameters: wParam (int i) is the index of the item. lParam (RECT FAR * prc) is the bounding rectangle. The int code member of the RECT structure specifies the portion of the list item for which you want to get the bounding rectangle. This can be one of the values listed in Table 6 below. The code portion is specified in the prc->left member of the RECT structure.
Table 6. List View Bounding Rectangle Options
Option | Meaning |
LVIR_BOUNDS | Get the bounding rectangle for the entire item, including the icon and the label. |
LVIR_ICON | Get the bounding rectangle for the icon only. |
LVIR_IMAGE | Get the bounding rectangle for the icon, but exclude the icon margin. |
LVIR_LABEL | Get the bounding rectangle for the icon label. |
LVIR_SELECTBOUNDS | Set the bounding rectangle to include the icon and the item text in the label such that when the user clicks within the rectangle, the item is selected. |
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetItemRect(hwndLV, i, prc, code);
wParam = i; \\ index of the item
lParam = UINT mask; \\ flag indicating which state flags to get
Description: The LVM_GETITEMSTATE message gets the state of a list view item.
Parameters: wParam (int i) is the index of the item. lParam (UINT mask) specifies which state flags to get.
Return value: The item's state flags, as described in Table 4, List View Item States, previously in this article.
Macro: (UINT)ListView_GetItemState(hwndLV, i, mask);
wParam = i; \\ index of the item
lParam = (LV_ITEM FAR *)plvi; \\ structure that receives the text
Description: The LVM_GETITEMTEXT message gets the item text of a list view item or subitem.
Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) is the item structure. This structure should have the iSubItem member filled in (if you want to get the text for a subitem) and the maximum number of characters to get. You must fill in the following members of the LV_ITEM structure:
Return value: The length of the item text.
Macro: (int)ListView_GetItemText(hwndLV, i, iSubItem, pszText, cchTextMax);
wParam = iStart; \\ index of item to start at
lParam = UINT flags; \\ relational flags
Description: The LVM_GETNEXTITEM message searches for the next list view item starting from a specified item. If an item does not have all of the specified state flags set, the search continues with the next item.
Parameters: wParam (int iStart) is the index of the item to start at, or –1 to start from the beginning. In lParam (UINT flags), flags specify the geometric relation of the requested item to the specified item and the state of the requested item. The geometric relation can be one of the values listed in Table 7 below. Note that the first five flags are mutually exclusive but can be used in combination with any of the remaining flags.
Table 7. List View Search Criteria
Value | Meaning |
LVNI_ALL | Search for a subsequent item based on the index. This is the default. |
LVNI_ABOVE | Search for an item that is above the specified item. |
LVNI_BELOW | Search for an item that is below the specified item. |
LVNI_TORIGHT | Search for an item to the right of the specified item. |
LVNI_TOLEFT | Search for an item to the left of the specified item. |
LVNI_FOCUSED | Return focused items. |
LVNI_SELECTED | Return selected items. |
LVNI_CUT | Return marked items. |
LVNI_HIDDEN | Return hidden items. |
LVNI_DROPHILITED | Return the drop-highlighted items. |
LVNI_PREVIOUS | Search backwards. |
Return value: The index of the next item if successful; –1 otherwise.
Macro: (int)ListView_GetNextItem(hwndLV, iStart, flags);
wParam = 0; \\ not used
lParam = (POINT FAR *)ppt; \\ structure receiving origin values
Description: The LVM_GETORIGIN message gets the list view origin, which is needed for setting the item position.
Parameters: wParam is not used. lParam (POINT FAR * ppt) specifies a structure that receives the origin values.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetOrigin(hwndLV, ppt);
wParam = 0; \\ not used
lParam = (LPCSTR)psz; \\ the string
Description: The LVM_GETSTRINGWIDTH message gets the minimum column width necessary to display the given string. The returned width takes the current font and column margins of the list view into account, but does not take the width of a small icon into account.
Parameters: wParam is not used. lParam (LPCSTR psz) specifies the string.
Return value: The column width if successful; 0 otherwise.
Macro: (int)ListView_GetStringWidth(hwndLV, psz);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETTEXTPKCOLOR message gets the background text color in a list view window.
Parameters: wParam and lParam are not used.
Return value: The background color of the text (COLORREF).
Macro: (COLORREF)ListView_GetTextBkColor(hwndLV);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETTEXTCOLOR message gets the color of the text in a list view window.
Parameters: wParam and lParam are not used.
Return value: The text color (COLORREF).
Macro: (COLORREF)ListView_GetTextColor(hwndLV);
wParam = 0; \\ not used
lParam = 0; \\ not used
Description: The LVM_GETTOPINDEX message gets the index of the first visible item in the list view.
Parameters: wParam and lParam are not used.
Return value: The index of the first visible item (int i).
Macro: (int)ListView_GetTopIndex(hwndLV, ppt);
wParam = 0; \\ not used
lParam = RECT FAR *prc; \\ bounding rectangle
Description: The LVM_GETITEMSTATE message gets the bounding rectangle of all of the items in a list view in icon view.
Parameters: wParam is not used. lParam (RECT FAR * prc) is the bounding rectangle. All coordinates are in list view client window units.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_GetViewRect(hwndLV, prc);
wParam = 0; \\ not used
lParam = (LV_HITTESTINFO FAR *)pinfo; \\ position to hit test
Description: The LVM_HITTEST message determines which list view item is at a specified position.
Parameters: wParam is not used. lParam (LV_HITTESTINFO FAR * pinfo) specifies the structure containing the position to hit test.
Return value: The index of the item at the specified position; –1 otherwise.
Macro: (int)ListView_HitTest(hwndLV, pinfo);
wParam = iCol; \\ index of the new column
lParam = 0; \\ not used
Description: The LVM_INSERTCOLUMN message inserts a new column in a list view window.
Parameters: wParam (int iCol) is the index of the new column. lParam (const LV_COLUMN FAR * pcol) specifies the structure containing column information.
Return value: The index of the new column; –1 if an error occurred.
Macro: (int)ListView_InsertColumn(hwndLV, iCol, pcol);
wParam = 0; \\ not used
lParam = (const LV_ITEM FAR *)pitem; \\ new item information
Description: The LVM_INSERTITEM message inserts a new item in a list view window.
Parameters: wParam is not used. lParam (const LV_ITEM FAR * pitem) specifies the structure containing item information. The iItem member specifies the index of the new item. The iSubItem member must be zero; this message cannot be used to insert subitems.
Return value: The index of the new item if successful; –1 otherwise.
Macro: (int)ListView_InsertItem(hwndLV, pitem);
wParam = 0; \\ not used
lParam = MAKELONG(iFirst, iLast); \\ range of items to redraw
Description: The LVM_REDRAWITEMS message forces a redraw of a range of list view items. The specified items are not actually repainted until the list view window receives a WM_PAINT message. To repaint immediately, call the UpdateWindow function after using this message.
Parameters: wParam is not used. In lParam (MAKELONG iFirst iLast) the high-order word is int iFirst—the index of the first item in the range to redraw. The low-order word is int iLast—the index of the last item in the range to redraw.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_RedrawItems(hwndLV, iFirst, iLast);
wParam = 0; \\ not used
lParam = MAKELONG(dx, dy); \\ horizontal and vertical scrolling
Description: The LVM_SCROLL message scrolls the contents of a list view window. If the current view is report view, the dx parameter must be zero and the dy parameter is the number of lines to scroll.
Parameters: wParam is not used. In lParam (MAKELONG dx dy), the high-order word is int dx—the amount of horizontal scrolling, in pixels. The low-order word is int dy—the amount of vertical scrolling, in pixels.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_Scroll(hwndLV, dx, dy);
wParam = 0; \\ not used
lParam = (COLORREF)clrBk; \\ background color to set
Description: The LVM_SETBKCOLOR message sets the background color of the list view window.
Parameters: wParam is not used. lParam (COLORREF clrBk) is the background color to set, or CLR_NONE for no background color. List views with background colors redraw themselves significantly faster than those without background colors.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetBkColor(hwndLV, clrBk);
wParam = UINT mask; \\ callback mask
lParam = 0; \\ not used
Description: The LVM_SETCALLBACKMASK message sets the callback mask for a list view window.
Parameters: wParam (UINT mask) is the new value of the callback mask. See Table 4, List View Item States, previously in this article for available masks. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetCallbackMask(lwndLV, mask);
wParam = iCol; \\ index of the column
lParam = (LV_COLUMN FAR *)pcol; \\ structure containing column attributes
Description: The LVM_SETCOLUMN message sets the attributes of a list view column.
Parameters: wParam (int iCol) is the index of the column. lParam (LV_COLUMN FAR *pcol) is the structure containing the new attributes. The mask member of the structure specifies which column attributes to set. If the mask member specifies the LVCF_TEXT flag, the pszText member is the address of a null-terminated string, and the cchTextMax is ignored.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetColumn(hwndLV, iCol, pcol);
wParam = iCol; \\ index of the column
lParam = cx; \\ new width
Description: The LVM_SETCOLUMNWIDTH message sets the width of a column in report view or list view.
Parameters: wParam (int iCol) is the index of the column. lParam (int cx) is the new width of the column.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetColumnWidth(hwndLV, iCol, cx);
wParam = iImageList; \\ LVSIL_SMALL, LVSIL_NORMAL, or LVSIL_STATE
lParam = (HIMAGELIST) himl; \\ handle of the image list
Description: The LVM_SETIMAGELIST message sets the image list used for drawing list view items.
Parameters: wParam (int ImageList) is LVSIL_SMALL for a small icons, LVSIL_NORMAL for standard icons, or LVSIL_STATE for a state image list. lParam (HIMAGELIST himl) is the handle to the image list.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetImageList(hwndLV, himl, iImageList);
wParam = 0; \\ not used
lParam = (const LV_ITEM FAR *)pitem; \\ new item attributes
Description: The LVM_SETITEM message sets a list view item's attributes.
Parameters: wParam is not used. lParam (const LV_ITEM FAR * pitem) specifies the structure that contains the new item attributes.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetItem(hwndLV, pitem);
wParam = cItems; \\ count of the items
lParam = 0; \\ not used
Description: The LVM_SETITEMCOUNT message sets the item count of a list view.
Parameters: wParam (int cItems) is the count of the items. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetItemCount(hwndLV, cItems);
wParam = i; \\ item index
lParam = MAKELONG(x, y); \\ top-left corner of the new item
Description: The LVM_SETITEMPOSITION message sets the position of a list view item in standard icon or small icon view relative to the list view rectangle.
Parameters: wParam (int i) is the index of the list view item. lParam (int x y) is the top-left corner of the new item in list view client coordinates. The high-order word is x, and the low-order word is y.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetItemPosition(hwndLV, i x, y);
wParam = i; \\ index of the item
lParam = (LV_ITEM FAR *)plvi; \\ new item state
Description: The LVM_SETITEMSTATE message sets the state of a list view item.
Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) specifies the two fields that need to be filled in, as follows:
Return value: TRUE if successful; FALSE otherwise. However, the message returns a VOID.
Macro: (VOID)ListView_SetItemState(hwndLV, I, data, mask);
wParam = i; \\ index of the item
lParam = (LV_ITEM FAR *)plvi; \\ new item text
Description: The LVM_SETITEMTEXT message sets the text of a list view item or subitem.
Parameters: wParam (int i) is the index of the item. lParam (LV_ITEM FAR * plvi) specifies the fields lvi.iSubItem and lvi.pszText. These fields should be filled in as follows:
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetItemText(hwndLV, I, iSubItem, pszText);
wParam = 0; \\ not used
lParam = (COLORREF)clrText; \\ new background text color
Description: The LVM_SETTEXTBKCOLOR message sets the background text color of a list view window.
Parameters: wParam is not used. lParam (COLORREF clrText) is the new background text color.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetTextBkColor(hwndLV, clrText);
wParam = 0; \\ not used
lParam = (COLORREF)clrText; \\ new text color
Description: The LVM_SETTEXTCOLOR message sets the text color in a list view window.
Parameters: wParam is not used. lParam (COLORREF clrText) is the new text color.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SetTextColor(hwndLV, clrText);
wParam = (LPARAM)lParamSort; \\ application-defined parameter
lParam = (PFNLVCOMPARE) pfnCompare; \\ sorting callback function
Description: The LVM_SORTITEMS message sorts list view items using an application-defined comparison function. The index of each item changes to reflect the new sequence. The comparison function must return a negative value if the first item should precede the second, a positive value if the first item should follow the second, or zero if the two items are equivalent. The lParam1 and lParam2 parameters correspond to the lParam member of the LV_ITEM structure for the two items being compared. The lParamSort parameter is identical to the value passed to the ListView_SortItems macro.
Parameters: wParam (LPARAM lParamSort) is the application-defined parameter that is passed to the comparison function. lParam (PFNLVCOMPARE pfnCompare) is a callback function that does the comparison. The comparison function has the following form:
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_SortItems(hwndLV, pfnCompare, lParamSort);
wParam = i; \\ index of the item
lParam = 0; \\ not used
Description: The LVM_UPDATE message updates a list view item. If the list view has the LVS_AUTOARRANGE style, the list view will be arranged.
Parameters: wParam (int i) is the index of the item to update. lParam is not used.
Return value: TRUE if successful; FALSE otherwise.
Macro: (BOOL)ListView_Update(hwndLV, i);
The following structures are used with the macros described in the previous section and with the notifications described in the next section. You will notice that most of these structures use masks heavily to determine the valid members of the structure. You will also notice that some masks can be used with more than one structure.
typedef struct _LV_COLUMN {
UINT mask; \\ specifies which members are valid
int fmt; \\ format of the column
int cx; \\ width of the column in pixels
LPSTR pszText; \\ column heading text
int cchTextMax; \\ size of text buffer
int iSubItem; \\ index of the subitem associated with the column
} LV_COLUMN;
The LV_COLUMN structure contains information about a column in report view. It can also be used to receive information about a column. This structure is used with the ListView_GetColumn, ListView_SetColumn, ListView_InsertColumn, and ListView_DeleteColumn macros. The LV_COLUMN structure includes the following members:
Table 8. List View Column Format Masks
Value | Meaning |
LVCF_ALL | All members of the structure are valid. |
LVCT_FMT | The .fmt member of the structure is valid. |
LVCF_WIDTH | The .cx member of the structure is valid. |
LVCF_TEXT | The .pszText member of the structure is valid. |
LVCF_SUBITEM | The .iSubItem member of the structure is valid. |
typedef struct _LV_DISPINFO {
NMHDR hdr; \\ common control notification structure
LV_ITEM item; \\ list view item
} LV_DISPINFO;
The LV_DISPINFO structure is used with the LVN_GETDISPINFO and LVN_SETDISPINFO notifications to get and set information about a list view item. These notifications are sent only if the parent window is responsible for maintaining certain information. The LV_DISPINFO structure includes the following members:
typedef struct _LV_DRAGITEMINFO {
HWND hwndRoot; \\ handle of the drag root window
HWND hwndFrom; \\ handle of the drag source window
UINT fmt; \\ format of the drag data
LPARAM lParam; \\ application-defined data
POINT ptOffset; \\ screen coordinates of where drag began
} LV_DRAGITEMINFO;
The LV_DRAGITEMINFO structure contains information about the item being dragged. This structure is used with the ListView_DragItem macro. The LV_DRAGITEMINFO structure includes the following members:
typedef struct _LV_FINDINFO {
UINT flags; \\ type of search to perform
LPCSTR psz; \\ string to compare with
LPARAM lParam; \\ value to compare with LV_ITEM's lParam member
} LV_FINDINFO;
The LV_FINDINFO structure contains information used to search for a list view item. This structure is used with the ListView_FindItem macro. The LV_FINDINFO structure includes the following members:
Table 9. List View Find Flags
Flag | Meaning |
LVFI_PARAM | Searches based on the lParam member. The lParam member of the matching item's LV_ITEM structure must match the lParam member of this structure. If this flag is specified, all other flags are ignored. |
LVFI_STRING | Searches based on item text. Unless additional flags are specified, the item text of the matching item must exactly match the string that the psz member points to. |
LVFI_SUBSTRING | Matches if the string the psz member points to is contained anywhere in the item text. This flag cannot be used with LVFI_PARTIAL. This flag implies LVFI_STRING. |
LVFI _PARTIAL | Matches if the item text begins with the string that the psz member points to. This flag implies LVFI_STRING. |
LVFI_NOCASE | Ignores case in string comparisons. This flag is ignored if LVFI_STRING is not specified. |
typedef struct _LV_HITTESTINFO {
POINT pt; \\ position to hit test
UINT flags; \\ receives results of hit test
} LV_HITTESTINFO;
The LV_HITTESTINFO structure contains information about a hit test. This structure is used with the ListView_HitTest macro. The structure includes the following members:
Table 10. List View Hit Test Flags
Flag | Meaning |
LVHT_NOWHERE | The position is inside the list view's client window but not over a list item. |
LVHT_ONITEMICON | The position is over a list item's icon. |
LVHT_ONITEMLABEL | The position is over a list item's text. |
LVHT_ONITEM | The position is on an item. This is a combination of LVHT_ONEITEMICON and LVHT_ONITEMLABEL. |
LVHT_ABOVE | The position is above the list view's client area. |
LVHT_BELOW | The position is below the list view's client area. |
LVHT_TORIGHT | The position is to the right of the list view's client area. |
LVHT_TOLEFT | The position is to the left of the list view's client area. |
typedef struct _LV_ITEM {
UINT mask; \\ mask specifying which members are valid
int iItem; \\ index of the item
int iSubItem; \\ index of the subitem
UINT state; \\ item state
UINT stateMask; \\ state of item
LPSTR pszText; \\ item text
int cchText; \\ size of text buffer
int iImage; \\ index of the icon image in the image list
LPARAM lParam; \\ application-defined item data
} LV_ITEM;
The LV_ITEM structure contains the attributes of a list view item. This structure is used by a number of macros (all of which send messages), including ListView_GetItem, ListView_SetItem, ListView_InsertItem, and ListView_DeleteItem. The LV_ITEM structure includes the following members:
Table 11. List View Item Masks
Value | Meaning |
LVIF_TEXT | The pszText member is valid. |
LVIF_IMAGE | The iImage member is valid. |
LVIF_PARAM | The lParam member is valid. |
LVIF_STATE | The state member is valid. |
typedef struct _LV_KEYDOWN {
NMHDR hdr; \\ common control notification structure
WORD wVKey; \\ virtual key code
UINT flags; \\ always zero
} LV_KEYDOWN;
The LV_KEYDOWN structure contains information about a keyboard event in a list view window. This structure is used with the LVN_KEYDOWN notification. The structure includes the following members:
typedef struct _NM_LISTVIEW {
NMHDR hdr; \\ common control notification structure
int iItem; \\ the list view item
int iSubItem; \\ the subitem
UINT uNewState; \\ new item state
UINT uOldState; \\ old item state
UINT uChanged; \\ which item attribute changed
POINT ptAction; \\ location where the event occurred
} NM_LISTVIEW;
The NM_LISTVIEW structure contains information about a list view notification. The address of this structure is specified as the lParam parameter of the WM_NOTIFY message for several list view notifications. The structure includes the following members:
Oh dear, yet another list. I promise that this is the last one (in this article). Feel free to skip this section if you are sick of reading lists. The following table lists the notification messages that Windows sends to list view windows. All of these notifications are sent via a WM_NOTIFY message to the list view window's parent window.
Table 12. List View Notification Messages
Message | Description |
LVN_BEGINDRAG | Sent when the user begins a drag-and-drop operation involving the left mouse button. |
LVN_BEGINLABELEDIT | Sent when the user begins to edit the label of an item. |
LVN_BEGINRDRAG | Sent when the user begins a drag-and-drop operation involving the right mouse button. |
LVN_COLUMNCLICK | Sent when the user clicks a column. |
LVN_DELETEALLITEMS | Sent when all items in the list view are deleted. |
LVN_DELETEITEM | Sent when an item is deleted. |
LVN_ENDDRAG | Sent when default processing for a drag-and-drop operation involving the left mouse button has ended. |
LVN_ENDLABELEDIT | Sent when the user finishes editing the label of an item. |
LVN_ENDRDRAG | Sent when default processing for a drag-and-drop operation involving the right mouse button has ended. |
LVN_GETDISPINFO | Requests that a list view's parent window provide information for displaying or sorting an item. |
LVN_INSERTITEM | Sent when a new item is inserted. |
LVN_ITEMCHANGED | Sent when an item has changed. |
LVN_ITEMCHANGING | Sent when an item is changing. Returning FALSE for this notification will disallow the change. |
LVN_KEYDOWN | Sent when a key has been pressed. |
LVN_SETDISPINFO | Sent when the parent window must update the information it maintains for an item. |
Now you know how to create and use the new list view and column header windows that are built into Windows 95. These two new windows will really help you give your application the same look as the Windows 95 shell. So, find some areas in your application that would benefit from this new look, and use the code that I have given you to add this functionality to your application. Be the first one on your block to adopt the visual appeal of the new shell, and sneer at those who stick to the old method of displaying information.
I am really excited about my next article, which covers image lists and the new tree view window. Finally, we are giving you the ability to create a hierarchical tree that is built into the system. It's about time. The article is called "Win32 Common Controls, Part 5: Image Lists and Tree View Windows."