Click here to Skip to main content
15,885,216 members
Articles / Desktop Programming / MFC

C functions to insert columns, items and subitems into a ListView control

Rate me:
Please Sign up or sign in to vote.
3.92/5 (12 votes)
2 Jan 2005GPL33 min read 71.8K   848   33   4
Win32 API and C.

Introduction

If you need to insert columns and items into a ListView control, well you have probably spent some time looking for the SDK code. Here is a short article that consists of two ready-to-use C functions:

  • fInsertListViewColumn to insert columns with strings into a ListView control.
  • fInsertListViewItem to insert items / sub items with strings into a ListView control.

Background

  • You should be familiar with C program compiling with Win32 API.
  • C language background: pointers, strings, functions such as sprintf and memset.
  • API background: functions such as GetClientRect, InvalidateRect, MessageBox, SendMessage, and structs like RECT, LVITEM, LVCOLUMN.

Using the code

Declare, create and resize a ListView control, i.e., a child window of type WC_LISTVIEW, of style, e.g., WS_BORDER | WS_CHILD | WS_VISIBLE | LVS_REPORT. You may CreateWindowEx the ListView, and/or include it in your Visual Studio project. This ListView will contain the text.

Bear in mind that in a ListView, you deal with columns, items and subitems. One column contains only items (usually, the leftmost column), all the other columns contain only subitems.

In the functions below, we use the keystone API function SendMessage along with LVM_INSERTCOLUMN, LVM_INSERTITEM and LVM_SETITEM messages to insert columns, items and subitems, respectively.

The functions are simple to understand, and come with embedded comments explaining what they do step by step. However, here are some elements:

Declaration of the functions:

C++
int fInsertListViewColumn(HWND hwndListView, 
    long lCol, int iPercent, unsigned char* text);
C++
int fInsertListViewItem(HWND hwndListView,long lLin, 
    long lCol, int iSubItemYesNo, unsigned char* text);

The parameters to the functions:

  • hwndListView is the handle for your ListView control,
  • lLin and lCol are the zero-based indices of the line and column, respectively,
  • iPercent is the width of the column you want to insert into the ListView control,
  • an item is inserted if iSubItemYesNo equals 0, a subitem if iSubItemYesNo equals 1,
  • text is the 'string' that the pszText member of the LVITEM and LVCOLUMN structs will point to.

You might also need these includes:

C++
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
(etc...)

Call the functions, e.g., like this - the following code will insert 5 columns and 8 lines (i.e., 5 columns, 8 items and 32 subitems):

C++
int iColumnsToInsert = 5, iLinesToInsert = 8, i, j;
unsigned char sListViewText[200];
// Remember 65 is ASCII decimal for 'A', 66 is 'B', etc.:
for (i=0; i<iColumnsToInsert; i++)
{
    sprintf(sListViewText, "%c (column)", 65 + i);
    // Columns are labeled 'A', 'B', ... , 'E':
    fInsertListViewColumn(hwndLV, i, 100 / iColumnsToInsert, sListViewText);
}
for (i=0; i<iColumnsToInsert; i++)
{
    for (j=0; j<iLinesToInsert; j++)
    {
        // Items / subitems are labeled 'A1', 'A2', ... , 'E8':
        if (i == 0) sprintf(sListViewText, "%c%d (item)", 65 + i, j + 1);
            else sprintf(sListViewText, "%c%d (subitem)", 65 + i, j + 1);
        // Here iSubItemYesNo=0 if i is 0; iSubItemYesNo=1 otherwise:
        fInsertListViewItem(hwndLV, j, i, i == 0 ? 0 : 1, sListViewText);
    }
}

Return values of the function:

  • 0 if it fails.
  • 1 if OK.

Here is the code for the first function:

C++
int fInsertListViewColumn(HWND hwndListView, long lCol, 
        int iPercent, unsigned char* text)
{
/*********************
* Local declarations *
*********************/

// LVCOLUMN struct (see MSDN for content):
LVCOLUMN lvcolumn;

// RECT struct, used in column width and 
// WM_PAINT jobs:
RECT rect;
// Enter the client area of the ListView 
//into the RECT structure:
GetClientRect(hwndListView, &rect);

// To appear in the caption of the MessageBox:
static unsigned char *sYourApplicationsName = "you name it :)";
// Error 'string' you can use to 'MessageBox' and/or to 
// 'fprintf' into a logfile:
unsigned char sErrorString[5000];

// Value to be returned after the function tried 
// to insert a column:
int iResult;

/*************************
* Minimum error checking *
*************************/

// iPercent adjustement before display, e.g.:
iPercent = iPercent > 10 ? min(iPercent, 90) : 10;

// Column width, with 'rect.right' the x-coordinate of 
// the lower-right corner of the RECT:
int iWidth = (int) (rect.right * (iPercent / 100.0));

// Check ListView handle:
if (hwndListView == NULL)
{
    sprintf(sErrorString, 
        "! Handle of ListView NULL (fInsertListViewColumn)");
    MessageBox(NULL, (LPSTR) sErrorString, 
        (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION);
    return(0);
}

/***********************************************
* Use a LVCOLUMN struct to describe the column *
* that you want to insert into the ListView    *
***********************************************/

// Initialize the LVCOLUMN struct (see LVCF_xxx and 
// LVCFMT_xxx values in MSDN):
memset(&lvcolumn, 0, sizeof(lvcolumn));
// Necessary mask values for this job:
lvcolumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
// Left-align the text:
lvcolumn.fmt = LVCFMT_LEFT;
// Point to the right address:
lvcolumn.pszText = text;
// Nota bene: you might want to check lCol value first
lvcolumn.iSubItem = lCol;
// Set column width:
lvcolumn.cx = iWidth;

// SendMessage returns the number (zero based) of the 
// column inserted, 
// or -1 if it fails:
if (SendMessage((HWND) hwndListView, (UINT) LVM_INSERTCOLUMN, 
   (WPARAM) (int) lCol, (LPARAM) &lvcolumn) == -1) 
           iResult = 0; else iResult = 1;

// Paints (updates) the client area of the ListView control:
InvalidateRect(hwndListView, &rect, TRUE);

// Returns either 1 (OK) or 0 (failed to insert column - e.g., 
// lCol too big):
return(iResult);
}

Here is the code for the second function:

C++
int fInsertListViewItem(HWND hwndListView, long lLin, 
   long lCol, int iSubItemYesNo, unsigned char* text)
{
/*********************
* Local declarations *
*********************/

// LVITEM struct (see MSDN for content):
LVITEM lvi;

// RECT struct, used in column width and WM_PAINT jobs:
RECT rect;
// Enter the client area of the ListView into
// the RECT structure:
GetClientRect(hwndListView, &rect);

// To appear in the caption of the MessageBox:
static unsigned char *sYourApplicationsName = "you name it :)";
// Error string you can use to 'MessageBox' and/or to 'fprintf' 
// into a logfile:
unsigned char sErrorString[5000];

// Value to be returned after the function tried to insert 
// an item / subitem:
int iResult;

/*************************
* Minimum error checking *
*************************/

// Check ListView handle:
if (hwndListView == NULL)
{
    sprintf(sErrorString, 
        "! Handle of ListView NULL (fInsertListViewItem)");
    MessageBox(NULL, (LPSTR) sErrorString, 
      (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION);
    return(0);
}

/*****************************************************
* Use a LVITEM struct to describe the item / subitem *
* that you want to insert into the ListView          *
*****************************************************/

// Initialize the LVITEM struct (see LVIF_xxx reference in MSDN):
memset(&lvi, 0, sizeof(lvi));
// Minimum mask value for this job:
lvi.mask = LVIF_TEXT;
lvi.state = 0;
lvi.stateMask = 0;
// Point to the right address:
lvi.pszText = text;
// Nota bene: you might want to check lLin and lCol values first
lvi.iItem = lLin;
lvi.iSubItem = lCol;
    
switch(iSubItemYesNo)
{
    case 0:
        // Send LVM_INSERTITEM message if you want to 
        // insert an item (returns -1 if it fails):
        if (SendMessage((HWND) hwndListView, 
           (UINT) LVM_INSERTITEM, (WPARAM) 0, (LPARAM) &lvi) == -1) 
                       iResult = 0; else iResult = 1;
        break;
    case 1:
        // Send LVM_SETITEM message if you want to insert 
        // a subitem (returns FALSE if it fails):
        if (SendMessage((HWND) hwndListView, 
           (UINT) LVM_SETITEM, (WPARAM) 0, (LPARAM) &lvi) == FALSE) 
                       iResult = 0; else iResult = 1;
        break;
    default:
      sprintf(sErrorString, 
        "! Unexpected iSubItemYesNo value: %d (fInsertListViewItem)", 
                                iSubItemYesNo);
      MessageBox(NULL, (LPSTR) sErrorString, 
        (LPSTR) sYourApplicationsName, MB_OK | MB_ICONEXCLAMATION);
      return(0);
      break;
}

// Paints (updates) the client area of the ListView control:
InvalidateRect(hwndListView, &rect, TRUE) ;

// Returns either 1 (OK) or 0 (failed to insert an item / subitem):
return(iResult);
}

Points of Interest

  • In MSDN, about inserting columns (title 'LVCOLUMN Structure (Windows Explorer and Controls)'):

    If a column is added to a list-view control with index 0 (the leftmost column) and with LVCFMT_RIGHT or LVCFMT_CENTER specified, the text is not right-aligned or centered. The text in the index 0 column is left-aligned.

  • If you write SDK programs, remember the MSDN warning about the GetMessage function:

    Because the return value can be nonzero, zero, or -1, avoid code like this:

    C++
    while (GetMessage( lpMsg, hWnd, 0, 0)) ...

    The possibility of a -1 return value means that such code can lead to fatal application errors. Instead, use the code like this:

    C++
    BOOL bRet;
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    }

References

  • Giannini M., Keogh J. Windows programming - Programmer's notebook. Prentice Hall PTR, 2001, pp. 381-407.
  • Bengi. Using ListView control under Win32 API (CodeProject article).
  • Petzold C. Programming Windows (fifth edition). Microsoft Press, 1999.
  • MSDN: keywords: CreateWindowEx --> ListView --> listview styles, messages, notifications.

History

  • December 24th, 2004: version 1.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
George Sand Hospital, Bourges
France France
Electronic health record, health classifications (diseases, procedures), database, diagnosis related groups.

Comments and Discussions

 
Generalthanks for your code Pin
raindropb_boy3-Dec-10 15:33
raindropb_boy3-Dec-10 15:33 
GeneralRe: thanks for your code Pin
Bruno Challier3-Dec-10 23:12
Bruno Challier3-Dec-10 23:12 
GeneralRe: thanks for your code Pin
raindropb_boy7-Dec-10 15:37
raindropb_boy7-Dec-10 15:37 
GeneralExcellent.. Pin
:GPS:8-Dec-05 20:32
:GPS:8-Dec-05 20:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.