windows sdk 编程系列文章 ----列表视图控件=>> 排序

排序项目/子项目

LVM_SORTITEMS
wParam = lParamSort
lParam = pCompareFunction

lParamSort 用户定义的值,该值将传递给用来比较的函数。
pCompareFunction 用户定义的用来比较排序的函数的地址。该函数的原型如下:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

lParam1 和 lParam2 是 LV_ITEM 型的结构体中的成员变量 lParam 的值。
lParamSort 是发送 LVM_SORTITEMS 消息时参数 wParam 中的值
当列表视图控件接收到 LVM_SORTITEMS 消息时,当需要比较项目时它会调用在 lParam 中指定的比较函数。比较函数将决定那一
个项目排在前面。方法很简单:如果函数返回一个负值,由(lParam 代表的)第一个项目排在前,如果返回正值,第二个项目
排在前。如果相等,必须返回 0 。
真正使得该方法能够运行的是 LV_ITEM 型结构体中的成员变量 lParam 值。当您需要排序时(譬如当您点击列的标题条时),您
需要考虑好排序方案。在本例中,我们把项目的索引放到该成员变量中,这样我们可以通过发送 LVM_GETITEM 消息来得到项目
的其它信息。注意:当项目重排序后,它们的索引也就变了。所以当重排序后,我需要在 lParam 参数中反应出新的索引。如果
您想在用户点击列的标题条时重新排序,您需要在您的窗口过程函数中处理 LVN_COLUMNCLICK 通知消息。LVN_COLUMNCLICK 消
息是随同 M_NOTIFY 消息一起发送的。

========
该例子创建了一个列表视图控件,并在其中显示了当前文件夹中的文件大小和文件名。缺省的视图是报告方式的,如果您点击
列标题条,标题将按升/降序重新排列。您可以通过菜单选择不同的显示方式(大图标、小图标等)。当您双击一个项目时,项
目的名称将显示在一个对话框中。

#include "Windows.h"
#include "tchar.h"
#include "commctrl.h"
#include "shlwapi.h"
#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"shlwapi.lib")
#define IDM_MAINMENU 10000
#define IDM_ICON LVS_ICON
#define IDM_SMALLICON LVS_SMALLICON
#define IDM_LIST LVS_LIST
#define IDM_REPORT LVS_REPORT
TCHAR ClassName[] = _T("ListViewWinClass");
TCHAR AppName[] = _T("Testing a ListView Control");
TCHAR ListViewClassName[] = _T("SysListView32");
TCHAR Heading1[] = _T("Filename");
TCHAR Heading2[] = _T("Size");
TCHAR FileNamePattern[] = _T("*.*");
TCHAR mytemplate[] = _T("%lu");
DWORD FileNameSortOrder;
DWORD SizeSortOrder;
HINSTANCE g_hInstance;
HWND hList;
HMENU hMenu;
void InsertColumn()
{
 LV_COLUMN lvc;
 lvc.mask = LVCF_TEXT | LVCF_WIDTH;
 lvc.pszText = Heading1;
 lvc.cx = 150;
 SendMessage(hList,LVM_INSERTCOLUMN,0,(LPARAM)&lvc);
 lvc.mask |= LVCF_FMT;
 lvc.fmt = LVCFMT_RIGHT;
 lvc.pszText = Heading2;
 lvc.cx = 100;
 SendMessage(hList,LVM_INSERTCOLUMN,1,(LPARAM)&lvc);
}
void ShowFileInfo(DWORD row,WIN32_FIND_DATA* lpFind)
{
 LV_ITEM lvi;
 CHAR buffer[20];
 lvi.mask = LVIF_TEXT | LVIF_PARAM;
 lvi.iItem = row;
 lvi.iSubItem = 0;
 lvi.pszText = lpFind->cFileName;
 lvi.lParam = row;
 SendMessage(hList,LVM_INSERTITEM,0,(LPARAM)&lvi);
 lvi.mask = LVIF_TEXT;
 lvi.iSubItem ++;
 wsprintf(buffer,mytemplate,lpFind->nFileSizeLow);
 lvi.pszText = buffer;
 SendMessage(hList,LVM_SETITEM,0,(LPARAM)&lvi);
}
void FillFileInfo()
{
 WIN32_FIND_DATA finddata;
 HANDLE fHandle;
 int i;
 BOOL bRet = TRUE;
 fHandle = FindFirstFile(FileNamePattern,&finddata);
 if(fHandle != INVALID_HANDLE_VALUE)
 {
 i = 0;
 while(bRet)
 {
 if(!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
 {
 ShowFileInfo(i,&finddata);
 i++;
 }
 bRet = FindNextFile(fHandle,&finddata);
 }
 FindClose(fHandle);
 }
}
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM SortType)    // 排序自定义替换
{
 TCHAR buffer[256];
 TCHAR buffer1[256];
 LV_ITEM lvi;
 INT iRet,iRet1,iRet2;
 lvi.mask = LVIF_TEXT;
 lvi.pszText = buffer;
 lvi.cchTextMax = 256;
 switch(SortType)
 {
 case 1:
	 lvi.iSubItem = 1;
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
	 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet1);
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
	 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet2);
	 iRet = iRet1 - iRet2;
 	break;
 case 2:
	 lvi.iSubItem = 1;
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
	 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet1);
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
	 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet2);
	 iRet = iRet2 - iRet1;
 	break;
 case 3:
	 lvi.iSubItem = 0;
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
	 lstrcpy(buffer1,buffer);
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
	 iRet = lstrcmpi(buffer1,buffer);
 	break;
 default:
	 lvi.iSubItem = 0;
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
	 lstrcpy(buffer1,buffer);
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
	 iRet = lstrcmpi(buffer,buffer1);
 	break;
 }
 return iRet;
}
void UpdatelParam()
{
 LV_ITEM lvi;
 int nCount = SendMessage(hList,LVM_GETITEMCOUNT,0,0);
 lvi.mask = LVIF_PARAM;
 lvi.iSubItem = 0;
 lvi.iItem = 0;
 while(nCount > 0)
 {
	 lvi.lParam = lvi.iItem;
	 SendMessage(hList,LVM_SETITEM,0,(LPARAM)&lvi);
	 lvi.iItem++;
	 nCount --;
 }
}
void ShowCurrentFocus()
{
	 LV_ITEM lvi;
	 TCHAR buffer[256];
	 int nIndex = SendMessage(hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
	 lvi.iItem = nIndex;
	 lvi.iSubItem = 0;
	 lvi.mask = LVIF_TEXT;
	 lvi.pszText = buffer;
	 lvi.cchTextMax = 256;
	 SendMessage(hList,LVM_GETITEM,0,(LPARAM)&lvi);
	 MessageBox(NULL,buffer,AppName,MB_OK);
}
LONG CALLBACK ProcWinMain( HWND hWnd,
 UINT Msg,
 WPARAM wParam,
 LPARAM lParam
)
{
 switch(Msg)
 {
 case WM_CREATE:
 	{
	 hList = CreateWindowEx(NULL,ListViewClassName,NULL,LVS_REPORT | WS_CHILD |WS_VISIBLE,
	 0,0,0,0,hWnd,NULL,g_hInstance,NULL);
	 InsertColumn();
	 FillFileInfo();
	 SendMessage(hList,LVM_SETTEXTCOLOR,0,(LPARAM)RGB(255,255,255));
	 SendMessage(hList,LVM_SETBKCOLOR,0,(LPARAM)RGB(0,0,0));
	 SendMessage(hList,LVM_SETTEXTBKCOLOR,0,(LPARAM)RGB(0,0,0));
	 hMenu = GetMenu(hWnd);
	 CheckMenuRadioItem(hMenu,IDM_ICON,IDM_LIST,IDM_REPORT,MF_CHECKED); //一种类似单选按钮的菜单,多个菜单项中,同时只有一个会被选中
 	}
 	break;
 case WM_DESTROY:
 	PostQuitMessage(0);
 	break;
 case WM_SIZE:
 	MoveWindow(hList,0,0,LOWORD(lParam),HIWORD(lParam),TRUE);
 	break;
 case WM_COMMAND:
	 if(lParam == 0)
	 {
	 LONG nStyle = GetWindowLong(hList,GWL_STYLE) ;
	 nStyle &= ~LVS_TYPEMASK;
	 nStyle |= LOWORD(wParam);
	 SetWindowLong(hList,GWL_STYLE,nStyle);
	 CheckMenuRadioItem(hMenu,IDM_ICON,IDM_LIST,LOWORD(wParam),MF_CHECKED);
	 }
 	break;
 case WM_NOTIFY:
 {
 NMHDR *pNm = (NMHDR *)lParam;
 if(pNm->hwndFrom == hList)
 {
 if(pNm->code == LVN_COLUMNCLICK)
 {
 NM_LISTVIEW *pLV = (NM_LISTVIEW *)lParam;
	 if(pLV->iSubItem == 1)
	 {
			 if(SizeSortOrder == 0 || SizeSortOrder == 2)
			 {
				 SendMessage(hList,LVM_SORTITEMS,1,(LPARAM)CompareFunc);
				 UpdatelParam();
				 SizeSortOrder = 1;
			 }
			 else
			 {
				 SendMessage(hList,LVM_SORTITEMS,2,(LPARAM)CompareFunc);
				 UpdatelParam();
				 SizeSortOrder = 2;
			 }
	 }
	 else
	 {
			 if(FileNameSortOrder == 0 || FileNameSortOrder == 4)
			 {
				 SendMessage(hList,LVM_SORTITEMS,3,(LPARAM)CompareFunc);
				 UpdatelParam();
				 FileNameSortOrder = 3;
			 }
			 else
			 {
				 SendMessage(hList,LVM_SORTITEMS,4,(LPARAM)CompareFunc);
				 UpdatelParam();
				 FileNameSortOrder = 4;
			 }
	 }
 }
 else if(pNm->code == NM_DBLCLK)
 	ShowCurrentFocus();
 }
 }
 break;
 default:
 return DefWindowProc(hWnd,Msg,wParam,lParam);
 }
 return 0;
}
int WINAPI WinMain( HINSTANCE hInstance,
 HINSTANCE hPrevInstance,
 LPSTR lpCmdLine,
 int nCmdShow
)
{
	 WNDCLASSEX wc;
	 MSG msg;
	 HWND hWnd;
	 InitCommonControls();
	 g_hInstance = hInstance;
	 wc.cbSize = sizeof(WNDCLASSEX);
	 wc.style = NULL;
	 wc.lpfnWndProc = ProcWinMain;
	 wc.cbClsExtra = NULL;
	 wc.cbWndExtra = NULL;
	 wc.hInstance = hInstance;
	 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	 wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU);
	 wc.lpszClassName = ClassName;
	 wc.hIcon = wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
	 wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	 RegisterClassEx(&wc);
	 hWnd = CreateWindowEx(NULL,ClassName,AppName,WS_OVERLAPPEDWINDOW,
	 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
 	 ShowWindow(hWnd,SW_SHOWNORMAL);
 	 UpdateWindow(hWnd);
	 while(GetMessage(&msg,NULL,0,0))
	 {
	 TranslateMessage(&msg);
	 DispatchMessage(&msg);
	 }
	 return msg.wParam;
}

分析:当主窗口创建后要做的第一件事是创建一个列表视图控件应用程序。

case WM_CREATE:
 {
	 hList = CreateWindowEx(NULL,ListViewClassName,NULL,LVS_REPORT | WS_CHILD |WS_VISIBLE,
	 0,0,0,0,hWnd,NULL,g_hInstance,NULL); 

我们调用 CreateWindowEx 来创建窗口,并把窗口类的名称“SysListView32”传给它。缺省的显示方式是报告方式,因为您指定了 LVS_REPORT 标志作为它的风格。

InsertColumn(); 

创建列表视图控件后,我们向其中插入列。

void InsertColumn()
{
	 LV_COLUMN lvc;
	 lvc.mask = LVCF_TEXT | LVCF_WIDTH;
	 lvc.pszText = Heading1;
	 lvc.cx = 150;
	 SendMessage(hList,LVM_INSERTCOLUMN,0,(LPARAM)&lvc); 
/*我们指定第一列的宽度和列的标题条,为了在该列中显示文件的名称,我们需要在 LV_COLUMN 型结构体变量的成员变量 Mask
中设定标志位 LVCF_TEXT 或 LVCF_WIDTH。我们设定 pszText 为列标题条文本字符串的值,cx 设定为列的宽度(以像素点为单
位)。然后我们发送 LVM_INSERTCOLUMN 消息给列表视图控件,并把该结构体变量传递给它。 
*/
	lvc.mask |= LVCF_FMT;
	lvc.fmt = LVCFMT_RIGHT;
/*
插入完第一列后,我们再插入第二列,单击该列的标题条可以按文件的大小排序。因为我们需要右对齐文本,我们需要在成员
变量 fmt 中指定标志位 LVCFMT_RIGHT。我们还必须在成员变量 Mask 中除了标志位 LVCF_TEXT 和 LVCF_WIDTH 外还需要指定标
志位 LVCF_FMT。 
*/
	lvc.pszText = Heading2;
	lvc.cx = 100;
	SendMessage(hList,LVM_INSERTCOLUMN,1,(LPARAM)&lvc);
} 
/*剩余的代码比较简单。在 pszText 中放入文本字符串的地址,在 cx 中放入列的宽度。然后发送消息 LVM_INSERTCOLUMN 给列表视图控件,在参数中同时传递列号和结构体变量的地址。当插入完列后,我们向列表控件中加入项目。*/
 FillFileInfo();
//FillFileInfo 的代码如下:
```cpp
void FillFileInfo()
{
	 WIN32_FIND_DATA finddata;
	 HANDLE fHandle;
	 int i;
	 BOOL bRet = TRUE;
	 fHandle = FindFirstFile(FileNamePattern,&finddata); 

我们调用 FindFirstFile 来得到第一个符合搜索标准的的文件的信息。FindFirstFile 函数的原型如下

HANDLE FindFirstFile( LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData );

lpFileName 是用来匹配搜索的文件名的地址。该字符串包含了通配符。在我们的例子中是*.*,这样会搜索当前文件夹中所有的文件。
lpFindData 是 WIN32_FIND_DATA 型的结构体变量的地址,WIN32_FIND_DATA 型的结构体变量将用来保存返回的文件的信息。
如果没有找到匹配的文件,该函数将返回 INVALID_HANDLE_VALUE 。否则将返回一个搜索句柄,您可以用该句柄在 FindNextFile函数中来搜索下一个符合条件的文件。

if(fHandle != INVALID_HANDLE_VALUE)
{
 i = 0;
 //如果找到了一个文件,我们在一个变量 fHandle 中保存搜索句柄,并把变量 i 清零,该变量 i 将用作项目的索引号。
 while(bRet)
 {
 if(!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
 {
//在本课中,我们将不处理文件夹,所以我们检查 dwFileAttributes 成员变量的值是否有 FILE_ATTRIBUTE_DIRECTORY 标志,如果有,我们就忽略掉它,然后调用 FindNextFile。
 ShowFileInfo(i,&finddata);
 i++;
 }
 bRet = FindNextFile(fHandle,&finddata);
 }
//我们调用 ShowFileInfo 函数包文件的名称和大小信息加到列表视图控件中去。然后让变量 i 加一来增加项目的行号。最后我们调用 FindNextFile 函数在当前文件夹中继续搜索文件一直到该函数返回 0 为止(这意味着没有可供搜索的文件了)。
 FindClose(fHandle);
 }
} 

当前文件夹中的文件枚举完毕后,我们必须关闭搜索句柄。
先在我们看一下 ShowFileInfo 函数。该函数由两个参数,一个是项目的索引号(也即行号),另一个是 WIN32_FIND_DATA 型结构体变量的地址。

void ShowFileInfo(DWORD row,WIN32_FIND_DATA* lpFind)
{
 LV_ITEM lvi;
 CHAR buffer[20];
 lvi.mask = LVIF_TEXT | LVIF_PARAM;
 lvi.iItem = row;
 lvi.iSubItem = 0;
//我们将传递项目的名称和 lParam 的值,所以我们在 Mask 中放入标志位 LVIF_TEXT 和 LVIF_PARAM。接下来我们在 iItem 中放入传递进来的行号,另外由于这是主项目我们必须设置 iSubItem 的值等于 0。
 lvi.pszText = lpFind->cFileName;
 lvi.lParam = row;
//我们现在要把标签字符串的地址,在这里也就是 WIN32_FIND_DATA 型结构体变量中的文件的名称放到 pszText 中。由于我们要完成对项目的排序,所以必须设置 lParam 的值,我把它设成行号值,这样我们可以根据索引值来查询项目。
 SendMessage(hList,LVM_INSERTITEM,0,(LPARAM)&lvi);
//设置完所有 LV_ITEM 型变量中的值后,我们发送 LVM_INSERTITEM 消息给列表视图控件来把项目插入到其中。
 lvi.mask = LVIF_TEXT;
 lvi.iSubItem ++;
 wsprintf(buffer,mytemplate,lpFind->nFileSizeLow);
 lvi.pszText = buffer;
/*我们将把子项目插入到第二列。一个子项目只能有一个标签。这样我们在 Mask 中指定 LVIF_TEXT 标志位。接着我们指定子项目所在的列,本例中我们通过将 iSubItem 加一使得该值等于 1。标签值是文件的大小,为了转换成文本我们调用 wsprintf 函数,然后把文本的地址放到 pszText 中去。*/
 SendMessage(hList,LVM_SETITEM,0,(LPARAM)&lvi);
}

当 LV_ITEM 型变量中的值设定好之后,我们向列表视图控件发送 LVM_SETITEM 消息,并一同把 LV_ITEM 变量的地址传过去。注意:发送的消息是 LV_ITEM 而不是 LVM_INSERTITEM,因为我们插入的是子项目,子项目不是真正的项目而是主项目的属性。所以我们这时是在设定项目的属性,而不是加入一个项目。
当所有的项目都插入到列表视图控件后,我们设定它的文本和背景颜色。

 SendMessage(hList,LVM_SETTEXTCOLOR,0,(LPARAM)RGB(255,255,255));
 SendMessage(hList,LVM_SETBKCOLOR,0,(LPARAM)RGB(0,0,0));
 SendMessage(hList,LVM_SETTEXTBKCOLOR,0,(LPARAM)RGB(0,0,0));

我们通过发送 LVM_SETTEXTCOLOR 和 LVM_SETTEXTBKCOLOR 消息来设定文本的前景和背景色。
hMenu = GetMenu(hWnd);
CheckMenuRadioItem(hMenu,IDM_ICON,IDM_LIST,IDM_REPORT,MF_CHECKED);
我们将让用户通过菜单来选择它想要的显示方式。这样我们必须先得到菜单的句柄。然后让用户跟踪当前的视图,我们在菜单中放入一组单选按钮。我们可以调用 CheckMenuRadioItem 函数,该函数将把一个单选按钮放到一个菜单项前。
注意我们创建列表视图控件时把它的宽度和高度都设成为 0。当父窗口改变大小时,它将同时改变大小。这样我们可以让列表视图总是随着主窗口改变。我们的例子中,我们让列表视图填充整个客户区。
case WM_SIZE:
MoveWindow(hList,0,0,LOWORD(lParam),HIWORD(lParam),TRUE);
break;
当父窗口接收到了 WM_SIZE 消息后,lParam 的底字部分包含了客户区新的宽和高。让后我们调用 MoveWindow 来改变列表视图控件的大小使得它覆盖整个的客户区。
当用户通过菜单选择了一种选择方式,我们必须相应地改变列表视图中的显示方式。我们调用 SetWindowLong 函数来设定新的风格。
case WM_COMMAND:
if(lParam == 0)
{
LONG nStyle = GetWindowLong(hList,GWL_STYLE) ;
nStyle &= ~LVS_TYPEMASK;
首先得到当前的风格,然后清除旧的风格。LVS_TYPEMASK 是 LVS_ICON+LVS_SMALLICON+LVS_LIST+LVS_REPORT 四种风格的集合。
这样当我们用当前的风格“与”“~ LVS_TYPEMASK”就等于清除了当前的显示风格。
在设计菜单时,我们使用了一些小技巧。我们包显示风格的常数串当作菜单的 ID 号
#define IDM_ICON LVS_ICON
#define IDM_SMALLICON LVS_SMALLICON
#define IDM_LIST LVS_LIST
#define IDM_REPORT LVS_REPORT
这样当父窗口接收到 WM_COMMAND 消息时,希望显示的风格值会当成菜单的 ID 号传递过来。
nStyle |= LOWORD(wParam);
在 wParam 中的低字部分是欲显示的风格.我们把希望显示的风格加到列表视图的风格中去(已经去除了旧的风格)。
SetWindowLong(hList,GWL_STYLE,nStyle);
调用 SetWindowLong 函数来设定新的风格。
CheckMenuRadioItem(hMenu,IDM_ICON,IDM_LIST,LOWORD(wParam),MF_CHECKED);
}
break;
我们需要在被选择的显示方式前放入单选按钮。如果要排序,我们必须处理 WM_NOTIFY 消息。
case WM_NOTIFY:
{
NMHDR *pNm = (NMHDR *)lParam;
if(pNm->hwndFrom == hList)
{
当我们接收到了 WM_NOTIFY 消息后,lParam 包含了指向 NMHDR 型结构体变量的指针。我们通过把列表视图控件的值和 NMHDR 型
结构体变量中的 hwndFrom 成员变量的值比较来判断,如果相等的话我们就可以确定消息是列表视图控件发送的。
if(pNm->code == LVN_COLUMNCLICK)
{
如果通知消息是列表视图控件发送的,我们检测该消息是否是 LVN_COLUMNCLICK。如果是,它意味着用户点击了列标题条。在接收到 LVN_COLUMNCLICK 消息后,我们假设 lParam 参数包含 NM_LISTVIEW 型结构体变量的指针,NM_LISTVIEW 型结构体是 NMHDR型结构体的扩展。我们需要知道用户单击了那一列,在 iSubItem 中的值即是列号,列的编号是从 0 开始的。
NM_LISTVIEW *pLV = (NM_LISTVIEW *)lParam;
if(pLV->iSubItem == 1)
{
if(SizeSortOrder == 0 || SizeSortOrder == 2)
在这里 iSubItem 的值是 1,它表示用户点击的是第二列,即文件的大小。我们用状态变量来保持当前的排序顺序。0 代表不用排序,1 代表升序,2 代表降序。如果该列中的项目/子项目以前没有排序或为降序,我们就把它设成升序。
SendMessage(hList,LVM_SORTITEMS,1,(LPARAM)CompareFunc);
我们发送消息 LVM_SORTITEMS 给列表视图控件,在 wParam 中传递 1,在 lParam 中传递比较函数的参数。注意 wParam 中的值是用户定义的,用户可以按自己的需要来解释,这里我们把它用作排序的方法。我们先来看看比较函数:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM SortType)
{
 TCHAR buffer[256];
 TCHAR buffer1[256];
 LV_ITEM lvi;
 INT iRet,iRet1,iRet2;
 lvi.mask = LVIF_TEXT;
 lvi.pszText = buffer;
 lvi.cchTextMax = 256;
 /*列表视图控件将传递需要比较的两个项目的 lParam(LV_ITEM 型结构体变量的成员变量)比较函数。您还记得吗?我们在 lParam中放置了
 醒目的索引号。这样我们利用这些索引号查询列表视图来得到项目信息。我们需要的消息是项目/子项目的标签文本。
	为此我们准备好 LV_ITEM 型结构体变量并在 Mask 中设置标志位 LVIF_TEXT ,在 pszText 中设置缓冲区的地址,在 cchTextMax中
	设置缓冲区的大小。*/
 switch(SortType)
 {
 case 1:
 lvi.iSubItem = 1;
 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
  /*如果 SortType 的值为 1 或 2,我们知道点击了那一列,1 代表根据文件的大小按升序排列所有的项目。2 的意思相反。这样我们
  指定 iSubItem 为 1(代表文件大小列)然后发送 LVM_GETITEMTEXT 消息给列表视图控件来得到在项目的标签文本串。*/
 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet1);
	//调用子定义的 StrToIntEx 函数来把字符串转换成一个 DWORD 值。它将在 iRet1 中返回转换后的值。
 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
 StrToIntEx(buffer,STIF_SUPPORT_HEX,&iRet2);
 iRet = iRet1 - iRet2;
 break;
  /*对 lParam2 中的值做同样的操作。当我们得到了两个文件的大小后,就可以比较它们了。比较的规则如下:
	 如果第一个项目放在前面,在 iRet 中返回一个负值
	 如果第二个项目放在前面,在 iRet 中返回一个正值
	 如果相等,在 iRet 中返回 0
	在我们这里,我们想按升序排列,所以我们只要简单地将第二个项目的文件大小减去第一个项目的文件大小,然后返回放在 iRet中的值。*/
 case 3:
	 lvi.iSubItem = 0;
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam1,(LPARAM)&lvi);
	 lstrcpy(buffer1,buffer);
	 SendMessage(hList,LVM_GETITEMTEXT,(WPARAM)lParam2,(LPARAM)&lvi);
	 iRet = lstrcmpi(buffer1,buffer);   //比较两个字符串大小
	 break;
  /*当用户点击文件名字列时,我们必须比较文件的名字。我们先得到文件的名字,然后调用 lstrcmpi 函数来比较,然后只要
  简单返回 lstrcmpi 的值,因为该函数比较使用的规则和我们的相同。
  lstrcmpi=>>返回值:若buffer1比buffer2小则返回值为负;  若buffer1比buffer2大则返回值为正;相等则返回值为0。
	当项目排序后,我们调用 UpdateParam 函数来更新所有项目的 lParam 的值来反应出最新的改变。*/
 	UpdatelParam();
 	SizeSortOrder = 1;
 	//该函数简单地枚举列表视图中所有的项目并且把它们 lParam 更新成项目的索引号。
 else if(pNm->code == NM_DBLCLK)
 ShowCurrentFocus();
 /*如果用户双击某个项目时,我们将显示一个消息框,上面有该项目的有关标签值。我们必须检查 NMHDR 中的 code 值是否是NM_DBLCLK。
 如果是,我们就得到它的标签值并显示在一个消息框中。*/
void ShowCurrentFocus()
{
	 LV_ITEM lvi;
	 TCHAR buffer[256];
	 int nIndex = SendMessage(hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);
 /*我们是怎么知道某个项目被双击的呢?当单击或双击某个项目时,它的状态被设成“焦点”。即使有多个项目被选中,也仅有
一个项目有焦点。我们的工作就是去找到那个有焦点的项目。我们发送 LVM_GETNEXTITEM 消息给列表视图控件,在 lParam 中
指定期望的状态。如果 wParam 中时-1 的话,表示要搜索所有的项目。有焦点的项目第索引号在 nIndex 中返回。*/
	 lvi.iItem = nIndex;
	 lvi.iSubItem = 0;
	 lvi.mask = LVIF_TEXT;
	 lvi.pszText = buffer;
	 lvi.cchTextMax = 256;
	 SendMessage(hList,LVM_GETITEM,0,(LPARAM)&lvi);
	 //发送 LVM_GETITEM 消息来得到标签。
	 MessageBox(NULL,buffer,AppName,MB_OK);
} 

最后我们在一个消息框中显示标签。
如果想在列表视图控件中显示图标,您可以阅读关于树型视图控件的课程。它们的步骤基本上是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值