用于在 ListView 控件中插入列、项目和子项目的 C 函数






3.92/5 (11投票s)
Win32 API 和 C。

引言
如果您需要在 ListView 控件中插入列和项目,那么您可能已经花了一些时间寻找 SDK 代码。这是一篇简短的文章,其中包含两个随时可用的 C 函数
- fInsertListViewColumn用于将带有字符串的列插入 ListView 控件。
- fInsertListViewItem用于将带有字符串的项目/子项目插入 ListView 控件。
背景
- 您应该熟悉使用 Win32 API 进行 C 程序编译。
- C 语言背景:指针、字符串、函数(例如 sprintf和memset)。
- API 背景:函数(例如 GetClientRect、InvalidateRect、MessageBox、SendMessage)和struct(例如RECT、LVITEM、LVCOLUMN)。
使用代码
声明、创建和调整 ListView 控件的大小,即类型为 WC_LISTVIEW 的子窗口,样式例如 WS_BORDER | WS_CHILD | WS_VISIBLE | LVS_REPORT。您可以 CreateWindowEx ListView,和/或将其包含在您的 Visual Studio 项目中。此 ListView 将包含文本。
请记住,在 ListView 中,您处理的是列、项目和子项目。一列仅包含项目(通常是最左边的列),所有其他列仅包含子项目。
在下面的函数中,我们使用关键 API 函数 SendMessage 以及 LVM_INSERTCOLUMN、LVM_INSERTITEM 和 LVM_SETITEM 消息来分别插入列、项目和子项目。
这些函数简单易懂,并带有嵌入式注释,逐步解释它们的作用。但是,这里有一些元素
函数的声明
int fInsertListViewColumn(HWND hwndListView, 
    long lCol, int iPercent, unsigned char* text);
int fInsertListViewItem(HWND hwndListView,long lLin, 
    long lCol, int iSubItemYesNo, unsigned char* text);
函数的参数
- hwndListView是您的 ListView 控件的句柄。
- lLin和- lCol分别是行和列的从零开始的索引。
- iPercent是您要插入到 ListView 控件中的列的宽度百分比。
- 如果 iSubItemYesNo等于 0,则插入项目;如果iSubItemYesNo等于 1,则插入子项目。
- text是- LVITEM和- LVCOLUMN- struct的- pszText成员将指向的“字符串”。
您可能还需要这些 include。
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
(etc...)
调用函数,例如像这样 - 以下代码将插入 5 列和 8 行(即 5 列,8 个项目和 32 个子项目)
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);
    }
}
函数的返回值
- 0 表示失败。
- 1 表示正常。
这是第一个函数的代码
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);
}
这是第二个函数的代码
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);
}
关注点
- 在 MSDN 中,关于插入列(标题为“LVCOLUMN Structure (Windows Explorer and Controls)”)如果将列添加到索引为 0(最左边的列)且指定了 LVCFMT_RIGHT或LVCFMT_CENTER的列表视图控件,则文本不会右对齐或居中对齐。索引 0 列中的文本是左对齐的。
- 如果您编写 SDK 程序,请记住 MSDN 关于 GetMessage函数的警告因为返回值可以是非零值、零或 -1,所以要避免像这样的代码 while (GetMessage( lpMsg, hWnd, 0, 0)) ... 返回值为 -1 的可能性意味着此类代码可能导致致命的应用程序错误。相反,使用像这样的代码 BOOL bRet; while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if (bRet == -1) { // handle the error and possibly exit } else { TranslateMessage(&msg); DispatchMessage(&msg); } }
参考文献
- Giannini M., Keogh J. Windows programming - Programmer's notebook. Prentice Hall PTR, 2001, pp. 381-407.
- Bengi. 使用 Win32 API 下的 ListView 控件(CodeProject 文章)。
- Petzold C. Programming Windows (fifth edition). Microsoft Press, 1999.
- MSDN:关键词:CreateWindowEx --> ListView --> listview 样式、消息、通知。
历史
- 2004 年 12 月 24 日th:版本 1。


