27win32编程基础——通用控件ListView的使用和通用控件的消息传递

这些常用的控件,叫标准控件。
其他不常用的控件,叫做通用控件,就放在一个dll中,windows通用控件,放在Comctl32.dll中使用的时候,要在文件头加
#include<commctrl.h> #pragma comment(lib,"comctl32.lib")
在vc6低版本中,在使用通用控件之前还要加代码
INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_WIN95_CLASSES; InitCOmmonControlsEx(&icex);
对控件使用初始化操作,vs2010版本中都不用加初始化代码,只用加头文件的2句代码即可。
一、以ListView举例用法:
#include <windows.h>
#include "resource.h"
#include<commctrl.h>
#pragma comment(lib,"comctl32.lib")
HINSTANCE hIns;
INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
hIns = hInstance;
DialogBox(hIns,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);
return 0;
}
void InitListView(HWND hwndDlg){
LVCOLUMN lvc;
HWND HlistV=GetDlgItem(hwndDlg,IDC_LIST2);
//
//设置ListView的风格,点击就会整行选中
SendMessage(HlistV, LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
//相当于宏,SendMessage相当于宏ListView_SetExtendedListViewStyle(HlistV,LVS_EX_FULLROWSELECT)
//第一列
lvc.mask = LVCF_TEXT | LVCF_WIDTH|LVCF_SUBITEM;
lvc.pszText = TEXT("进程"); //列标题
lvc.cx = 80; //列宽
lvc.iSubItem =0; //第0列
SendMessage(HlistV, LVM_INSERTCOLUMN, 0, (DWORD)&lvc);
//第2列
lvc.pszText = TEXT("PID");
lvc.cx = 60;
lvc.iSubItem =1;
SendMessage(HlistV, LVM_INSERTCOLUMN, 1, (long)&lvc);
//第3列
lvc.mask = LVCF_TEXT | LVCF_WIDTH|LVCF_SUBITEM;;
lvc.pszText = TEXT("镜像基址");
lvc.cx = 60;
lvc.iSubItem =2;
//SendMessage(HlistV, LVM_INSERTCOLUMN, 2, (long)&lvc);
ListView_InsertColumn(HlistV,2, (long)&lvc);
//第4列
lvc.pszText = TEXT("镜像大小");
lvc.cx = 60;
lvc.iSubItem =3;
//SendMessage(HlistV, LVM_INSERTCOLUMN, 3, (long)&lvc);
ListView_InsertColumn(HlistV,3, (long)&lvc);
//设置背景颜色
SendMessage(hwndDlg, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
SendMessage(hwndDlg, LVM_SETBKCOLOR, 0, RGB(135, 160, 135));
SendMessage(hwndDlg, LVM_SETTEXTBKCOLOR, 0, RGB(60, 100, 130));
struct STUDENTINFO
{
TCHAR name[15];
TCHAR age[4];
TCHAR dept[20];
TCHAR job[20];
};
STUDENTINFO stu[6] = {
{ TEXT("无忌"), TEXT("20"),TEXT("技术部"), TEXT("工程师") },
{ TEXT("三丰"), TEXT("80"), TEXT("总经理"), TEXT("总经理") },
{ TEXT("远桥"), TEXT("40"), TEXT("技术部"), TEXT("经理") },
{ TEXT("敏敏"), TEXT("18"), TEXT("客服部"), TEXT("经理") },
{ TEXT("芷若"), TEXT("18"), TEXT("行政部"), TEXT("经理") },
{ TEXT("小昭"), TEXT("16"), TEXT("经理"), TEXT("前台") }
};
//往里面填充内容,需要结构体LVITEM
LVITEM vitem;
vitem.mask = LVIF_TEXT; //填入文本
for (int i = 0; i < 6; i++)
{
vitem.iItem = i; //第几行填充内容
//先添加项再设置子项内容
vitem.iSubItem = 0; //第几列
vitem.pszText = stu[i].name;
ListView_InsertItem(HlistV, &vitem); //只有第1列使用的是ListView_InsertItem,后边都是ListView_SetItem
//SendMessage(HlistV, LVM_INSERTITEM, 2, (long)&vitem);
// 设置子项
vitem.iSubItem = 1;
vitem.pszText = stu[i].age;
ListView_SetItem( HlistV, &vitem); //宏,可以F12看一下,和SendMessag是一样的
vitem.iSubItem = 2;
vitem.pszText = stu[i].dept;
//ListView_SetItem(HlistV, &vitem);
SendMessage(HlistV, LVM_SETITEM, 2, (long)&vitem);//必须使用LVM_SETITEM,只有第一列是使用LVM_INSERTITEM
//SendMessage(HlistV, LVM_INSERTITEM, 2, (long)&vitem);//
vitem.iSubItem = 3;
vitem.pszText = stu[i].job;
ListView_SetItem(HlistV, &vitem);
}
};
void EnumModules(HWND hwnd,WPARAM wParam,LPARAM lParam){
DWORD dwRowId;
TCHAR szPid[0x20];
LVITEM lv;
//初始化结构
memset(&lv,0,sizeof(LVITEM));
memset(szPid,0,0x20);
//获取选择的行,也可以使用ListView_GetNextItem(hwnd,LVNI_SELECTED )
dwRowId = SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_SELECTED);
dwRowId = ListView_GetNextItem(hwnd,-1,LVNI_SELECTED);
//dwRowId =ListView_GetNextItem(hwnd,-1,LVM_GETNEXTITEM);
if(dwRowId==-1)
{
MessageBox(NULL,TEXT("请选择进程"),TEXT("出错啦"),MB_OK);
return;
}
//获取选择的行中,pid这一列的内容
lv.iSubItem = 1;
lv.pszText = szPid;
lv.cchTextMax = 0x20;
SendMessage(hwnd,LVM_GETITEMTEXT,dwRowId,(DWORD)&lv);
MessageBox(NULL,szPid,TEXT("PID"),MB_OK);
};
INT_PTR CALLBACK DialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam){
HICON hicBig;
switch(uMsg){
case WM_CLOSE:
{
EndDialog(hwndDlg,0);
break;
}
case WM_INITDIALOG:
{
hicBig = LoadIcon(hIns, MAKEINTRESOURCE(IDI_ICON1));
SendMessage(hwndDlg,WM_SETICON,ICON_BIG,DWORD(hicBig));
SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,DWORD(hicBig));
InitListView(hwndDlg);
break;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BUTTON_PE:
return true;
case IDC_BUTTON_ABOUT:
return true;
case IDC_BUTTON_EXIT:
EndDialog(hwndDlg,0);
return true;
}
break;
case WM_NOTIFY:
//当时WM_NOTIFY的时候lParam指向NMHDR结构体
NMHDR* pNMHDR = (NMHDR*)lParam;
//判断是否是控件ListView和点击了ListView
if(wParam == IDC_LIST2 && pNMHDR->code==NM_CLICK)
{
EnumModules(GetDlgItem(hwndDlg,IDC_LIST2),wParam,lParam);
}
break;
}
return FALSE;
};
列表视图控件是一种非常常用的控件,在需要以报表形式显示数据时,列表控件通常是最好的选择,许多专用的数据报表控件,也是在它的基础上派生而来。与树视图类似,列表控件可以由多个子项目组成,可以设置为Icon(大图标)、SmallIcon(小图标)、List(列表)或Report(报表)。
一、列表视图控件有两个重要的数据结构LVCOLUMN和LVITEM。LVCOLUMN用于定义报表方式下的“列”的结构;LVITEM用于定义“项”的结构。这两个结构的定义及说明如下:
typedef struct _LVCOLUMN {
UINT mask; 说明此结构中哪些成员是有效的
int fmt; 列的对齐方式
int cx; 列的初始宽度
LPTSTR pszText; 列的标题
int cchTextMax; pszText所指向的缓冲区的大小
int iSubItem; 与列关联的子项的索引值,从0开始
int iImage; 与列关联的图像列表中指定图像的索引值
int iOrder; 第几列,0代表最左一列
} LVCOLUMN, FAR LPLVCOLUMN;
-----------------------------------
typedef struct _LVITEM {
UINT mask; 说明LVITEM结构中哪些成员有效
int iItem; 项目的索引值(可以视为行号)从0开始
int iSubItem; 子项的索引值(可以视为列号)从0开始
UINT state; 子项的状态
UINT stateMask; 状态有效的屏蔽位
LPTSTR pszText; 主项或子项的名称
int cchTextMax; pszText所指向的缓冲区大小
int iImage; 关联图像列表中指定图像的索引值
LPARAM lParam; 程序定义的32位参数
int iIndent; 表示图像位置缩进的单位
} LVITEM, FAR LPLVITEM;
二、相关操作。因为是SDK编程,所以对控件的操作是向控件发送SendMessage()来实现的 LISTVIEW中的相关消息为: 1、LVM_SETTEXTCOLOR 和 LVM_SETTEXTBKCOLOR和 LVM_SETBKCOLOR //消息设定文本的前景和背景色,wParam 为0,lParam 为颜色的RGB值 2、 LVM_GETNEXTITEM //找到选中的行,对应ListView_GetNextItem宏将SendMessage打包为函数方式操作。 3、LVM_SETCOLUMNWIDTH //设置列宽,对应ListView_SetColumnWidth 4、LVM_SETEXTENDEDLISTVIEWSTYLE //设置扩展风格如:LVS_EX_FULLROWSELECT(选中一整行), LVS_EX_GRIDLINES(网络线),LVS_EX_CHECKBOXES(选择按钮),对应ListView_SetExtendedListViewStyle 5、LVM_INSERTCOLUMN //插入新列,对应ListView_InsertColumn,wParam 为整型,指定列号,lParam 为指向LV_COLUMN结构的指针 6、LVM_SETCOLUMN //设置列,参数同上 7、LVM_INSERTITEM //插入项目(行),对应ListView_InsertItem,加入项目或子项目,wParam 为0,lParam 为指向LV_ITEM结构的指针 8、LVM_SETITEM //设置子项(行中的每列),对应ListView_SetItem,设置项目或子项目,参数同上 9、LVM_GETITEM //取得项目或子项目,参数同上 10、LVM_GETITEMCOUNT //获取项数,对应ListView_GetItemCount 11、LVM_GETNEXTITEM 取得下一个项目或子项目,可以用来取得光标选择的项目 12、LVM_DELETEITEM //删除项,对应ListView_DeleteItem,删除项目或子项目,wParam 为整型,指定项目索引号,lParam 为0 13、LVM_DELETEALLITEMS //删除所有项目,wParam 和 lParam 均为0 三、ListCtrl控件的扩展样式 LVS_EX_GRIDLINES //绘制表格线 LVS_EX_SUBITEMIMAGES//子项目图标列表 LVS_EX_CHECKBOXES //带复选框 LVS_EX_TRACKSELECT //自动换行 LVS_EX_HEADERDRAGDROP//报表头可以拖拽 LVS_EX_FULLROWSELECT //选择整行 LVS_EX_ONECLICKACTIVATE//单击激活 LVS_EX_TWOCLICKACTIVATE//双击激活 LVS_EX_FLATSB//扁平滚动条 LVS_EX_REGIONAL LVS_EX_INFOTIP LVS_EX_UNDERLINEHOT LVS_EX_UNDERLINECOLD LVS_EX_MULTIWORKAREAS//多工作区
二、LiveView等通用控件的消息,不再是使用WM_COMMAND而是WM_NOTIFY

点击ListView中不同的位置,应该如何处理这种消息呢?
之前的子窗口是通过WM_COMMAND转向父窗口发送的。
但是像ListView这种复杂控件就不能这样的,因此不同的位置,包含的消息信息比较多,使用W_COMMAND,不能包含复杂的消息信息,就产生了WM_NOTIFY消息。
WM_NOTIFY消息与WM_COMMAND类似,都是由子窗口向父窗口发送的消息。
但是WM_NOTIFY包含的消息信息比WM_COMMAND更多、更丰富
Windows中通用组件中很多消息,都是通过WM_NOFITY来描述的,而不是使用WM_COMMAND
当为WM_NOTIFY消息的时候,WPARAM wParam是控件ID,LPARAM lParam指向一个消息扩充的结构体:NMHDR、NMLVCACHEHINT 、NMLVDISPINFO、NMLVFINDITEM
typedef struct tagNMHDR {
HWND hwndFrom; //发送消息通知的控制窗口句柄
UINT_PTR idFrom; //发送通知消息的控制ID值
UINT code; //通知码,做的什么事情,左键还是右键,选中,例如WM_SELCHANGED
} NMHDR;
如果这些消息描述的信息内容还不够,windows还有扩充了另外一些消息结构
typedef struct tagNMLVCACHEHINT {
NMHDR hdr; 像不像继承,这就是c语言写的继承的方法
int iFrom;
int iTo;
} NMLVCACHEHINT, *PNMLVCACHEHINT;
typedef struct tagNMLVDISPINFO {
NMHDR hdr;
LVITEM item;
} NMLVDISPINFO;
typedef struct _NMLVFINDITEM {
NMHDR hdr;
int iStart;
LVFINDINFO lvfi;
} NMLVFINDITEM, *PNMLVFINDITEM;
例如:
NMLVDISPINFO 是 Windows API 中的一个消息类型,用于在列表视图控件(如 ListView)中显示信息。它通常用于自定义列表视图项的显示方式。
在编程中使用 NMLVDISPINFO 消息,你需要按照以下步骤进行:
包含头文件 windows.h 以访问所需的 API。
创建一个消息处理函数,该函数将处理 NMLVDISPINFO 消息。函数签名应如下所示:
c++
void OnDisplayInfo(NMLVDISPINFO* pDispInfo);
在你的代码中,使用 SetWindowLong 或 SetWindowLongPtr 函数将该消息处理函数与 NMLVDISPINFO 消息关联起来。例如:
c++
HWND hwnd = CreateWindowEx(0, L"MyWindowClass", L"NMLVCACHEHINT Example", WS_OVERLAPPEDWINDOW, 0, 0, 300, 300, nullptr, nullptr, nullptr, nullptr);//先不定义回调函数,然后使用SetWindowLong定义回调函数。
SetWindowLong(m_hWnd, GWL_WNDPROC, OnDisplayInfo);
在消息处理函数中,解析 NMLVDISPINFO 结构以获取有关消息的信息。你需要关注以下字段:
hdr:消息的头部信息,包括消息类型和其他信息。
item:LVITEM 结构,表示要显示的项目信息。它包含了文本、图像、状态等信息。你可以使用 item.pszText 获取文本信息,并根据需要修改其他字段。
iItem:要显示的项目索引。
iSubItem:要显示的子项索引。如果你的列表视图只包含一个列,则该字段通常为 0。
根据需要自定义项目的显示方式。你可以修改 item.pszText 字段来改变文本的显示内容,或者根据其他字段的值来自定义其他显示属性。
返回 TRUE 以指示消息已被处理。如果你返回 FALSE,则消息将被传递给下一个窗口处理函数。
以下是一个简单的示例代码片段,展示了如何使用 NMLVDISPINFO 消息自定义列表视图项的显示方式:
c++
#include <windows.h>
LRESULT CALLBACK OnDisplayInfo(NMLVDISPINFO* pDispInfo)
{
// 获取消息头部信息
const NMHDR& hdr = pDispInfo->hdr;
// 获取要显示的项目信息
const LVITEM& item = pDispInfo->item;
TCHAR szText[256]; // 假设文本不超过 256 个字符
// 根据需要修改项目的显示方式
switch (item.iSubItem)
{
case 0: // 修改第一列的显示内容
if (item.iItem % 2 == 0)
{
_tcscpy_s(szText, _T("Modified Text "));
_tcscat_s(szText, _T("Item "));
_tcscat_s(szText, item.pszText);
}
else
{
_tcscpy_s(szText, item.pszText);
}
break;
default: // 其他子项的显示方式保持不变
_tcscpy_s(szText, item.pszText);
break;
}
// 设置显示文本并返回 TRUE 表示消息已处理
ListView_SetItemText(pDispInfo->hdr.hwndFrom, item.iItem, item.iSubItem, szText);
return TRUE;
}

浙公网安备 33010602011771号