组合框和列表框同样也是控件,所以我们在应用组合框和列表框时同样也需要父窗口,现在我们以创建桌面程序项目时程序自行创建的窗口作为父窗口展开如下的控件创建与应用
在进行组合框与列表框的讲解前,我们首先在程序中定义几个宏作为我们在编写程序时的控件ID,这样会方便我们找到我们需要的控件:
#define IDC_BUTTON_CHECK_1 0
#define IDC_BUTTON_CHECK_2 1
#define IDC_BUTTON_CHECK_3 2
#define IDC_COMBOBOX_CITY 0x8001
#define IDC_LIST_COMM 0x9001//下拉框ID,注意ID范围在十六位以内,这是因为wParam低位只有十六位
组合框的创建
组合框(COMBOBOX):也叫下拉框,用于指定由列表框和类似于编辑控件的选择字段组成的控件。主要分为以下三种:
1.简单下拉框
2.拖拽下拉框
3.下拉列表
下图便是一个组合框:
当我们需要创建组合框时,在窗口主过程中的WM_CREATE消息进行创建,如下我们创建一个简单下拉框:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建组合框
HWND hWndCombobox = CreateWindow(L"Combobox", L"", WS_CHILD | WS_VISIBLE |WS_OVERLAPPED | CBS_DROPDOWN | CBS_HASSTRINGS, 100, 100, 200,200,hWnd, (HMENU)IDC_COMBOBOX_CITY, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
此时我们便创建了一个普通的组合框
接下来,我们为该组合框填充内容,使之更为完整
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建控件
HWND hWndCombobox = CreateWindow(L"Combobox", L"", WS_CHILD | WS_VISIBLE |WS_OVERLAPPED | CBS_DROPDOWN | CBS_HASSTRINGS, 100, 100, 200,200,hWnd, (HMENU)IDC_COMBOBOX_CITY, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
const WCHAR * szCity[5] = { L"北京",L"上海", L"深圳", L"广州", L"曹县" }; //此时我们创建了一个数组用于保存我们要填充的消息
for (size_t i = 0; i < 5; i++)
{
SendMessage(hWndCombobox,CB_ADDSTRING,NULL,(LPARAM)szCity[i]); //给下拉框发送添加字符串的消息
}
SendMessage(hWndCombobox, CB_SETCURSEL, 0, NULL); //设置默认选中的字符串,第三个参数是要传送的第0个字符串北京
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
组合柜的应用
组合框的消息处理在WM_COMMAND中进行获取对于应用的消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建控件
HWND hWndCombobox = CreateWindow(L"Combobox", L"", WS_CHILD | WS_VISIBLE |WS_OVERLAPPED | CBS_DROPDOWN | CBS_HASSTRINGS, 100, 100, 200,200,hWnd, (HMENU)IDC_COMBOBOX_CITY, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
const WCHAR * szCity[5] = { L"北京",L"上海", L"深圳", L"广州", L"曹县" }; //此时我们创建了一个数组用于保存我们要填充的消息
for (size_t i = 0; i < 5; i++)
{
SendMessage(hWndCombobox,CB_ADDSTRING,NULL,(LPARAM)szCity[i]); //给下拉框发送添加字符串的消息
}
SendMessage(hWndCombobox, CB_SETCURSEL, 0, NULL); //设置默认选中的字符串,第三个参数是要传送的第0个字符串北京
}
break;
case WM_COMMAND:
{
if (HIWORD(wParam) == CBN_SELCHANGE) //判断是不是下拉框的选择消息,CBN_SELCHANGE:当用户更改组合框列表框中的当前选择时发送的通知代码
{
if (LOWORD(wParam) == IDC_COMBOBOX_CITY) //判断是不是我们使用的下拉框
{
int ItemIndex = SendMessage((HWND)lParam, CB_GETCURSEL, NULL, NULL); //发送消息获取当前选择的索引
WCHAR *szCityName = new WCHAR[50];//用于接收选择选项的文本
SendMessage((HWND)lParam, CB_GETLBTEXT, ItemIndex, (LPARAM)szCityName);
//发送消息,获取指定索引的值
MessageBox(hWnd, szCityName, L"Msg", MB_OK); //对获取的值进行显示
}
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
完成以上代码后,我们在下拉框列表中选择相应的值时,会弹出相应的窗口。关闭弹窗后,组合框中文本修改为我们选择中的选项
列表的创建
使用该控件时需要包含头文件#include
接下来我们逐步创建一个报表类型的列表
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建列表
HWND hWndListView = CreateWindow(L"SysListView32", L"", LVS_REPORT | WS_CHILD |WS_VISIBLE | WS_BORDER, 10, 10, 400, 300, hWnd, (HMENU)IDC_LIST_COMM,((LPCREATESTRUCT)lParam)->hInstance, NULL);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
此时生成了一个空白列表
由于该列表是一个空白列表,因此接下来我们开始往里面添加内容
列表风格的设置
首先我们要设置列表的风格
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建列表
HWND hWndListView = CreateWindow(L"SysListView32", L"", LVS_REPORT | WS_CHILD |WS_VISIBLE | WS_BORDER, 10, 10, 400, 300, hWnd, (HMENU)IDC_LIST_COMM,((LPCREATESTRUCT)lParam)->hInstance, NULL);
//设置列表风格
LRESULT lStyle = SendMessage(hWndListView, LVM_GETEXTENDEDLISTVIEWSTYLE,NULL, NULL); //获取原有风格
lStyle |= (LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//注意或等
SendMessage(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, NULL, lStyle); //设置风格
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
此时我们已经设置好了列表的风格
列表表头的填写
通常我们有2种方式对表头的填写:1.消息,2.宏
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建列表
HWND hWndListView = CreateWindow(L"SysListView32", L"", LVS_REPORT | WS_CHILD |WS_VISIBLE | WS_BORDER, 10, 10, 400, 300, hWnd, (HMENU)IDC_LIST_COMM,((LPCREATESTRUCT)lParam)->hInstance, NULL);
//设置列表风格
LRESULT lStyle = SendMessage(hWndListView, LVM_GETEXTENDEDLISTVIEWSTYLE,NULL, NULL); //获取原有风格
lStyle |= (LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//注意或等
SendMessage(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, NULL, lStyle); //设置风格
//设置表头
LV_COLUMN lvc = { 0 }; //初始化LV_COLUMN表头结构,用来填充字符串
lvc.mask |= (LVCF_TEXT | LVCF_WIDTH); //mask设置标记,标记表头可以填充什么类型,此处为填充文本类型或图标
lvc.pszText = new WCHAR[50]; //开辟填充文本需要的空间
lvc.cx = 100; //设置列宽,即单个表头所占长度
memset(lvc.pszText, 0, 50); //初始化申请表头文本空间
memcpy(lvc.pszText, L"List1", 12);//在表头中填充字符串
//消息填写表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc); //发送插入列消息,在目标列表第0列插入表头
memset(lvc.pszText, 0, 50);//初始化表头
memcpy(lvc.pszText, L"List2", 12);//填充表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List3", 12);
SendMessage(hWndListView, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List4", 12);
//宏填写表头
ListView_InsertColumn(hWndListView, 3, &lvc); //利用宏的方式填充表头
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
此时便有了四个表头
列表内容的填充
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建列表
HWND hWndListView = CreateWindow(L"SysListView32", L"", LVS_REPORT | WS_CHILD |WS_VISIBLE | WS_BORDER, 10, 10, 400, 300, hWnd, (HMENU)IDC_LIST_COMM,((LPCREATESTRUCT)lParam)->hInstance, NULL);
//设置列表风格
LRESULT lStyle = SendMessage(hWndListView, LVM_GETEXTENDEDLISTVIEWSTYLE,NULL, NULL); //获取原有风格
lStyle |= (LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//注意或等
SendMessage(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, NULL, lStyle); //设置风格
//设置表头
LV_COLUMN lvc = { 0 }; //初始化LV_COLUMN表头结构,用来填充字符串
lvc.mask |= (LVCF_TEXT | LVCF_WIDTH); //mask设置标记,标记表头可以填充什么类型,此处为填充文本类型或图标
lvc.pszText = new WCHAR[50]; //开辟填充文本需要的空间
lvc.cx = 100; //设置列宽,即单个表头所占长度
memset(lvc.pszText, 0, 50); //初始化申请表头文本空间
memcpy(lvc.pszText, L"List1", 12);//在表头中填充字符串
//消息填写表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc); //发送插入列消息,在目标列表第0列插入表头
memset(lvc.pszText, 0, 50);//初始化表头
memcpy(lvc.pszText, L"List2", 12);//填充表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List3", 12);
SendMessage(hWndListView, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List4", 12);
//宏填写表头
ListView_InsertColumn(hWndListView, 3, &lvc); //利用宏的方式填充表头
//列表填充内容
LVITEM vItem = { 0 }; //初始化LVITEM项结构,该结构用于列表中填充文本
vItem.mask = LVIF_TEXT; //标记该项可填充文本
//表头设置了宽度后,项就不需要设置了
vItem.pszText = new WCHAR[50]; //开辟填充文本需要的空间
for (size_t i = 0; i < 10; i++)//通过循环每行每列都填充文本
{
vItem.iItem = i; //表示第几行进行插入文本内容
vItem.iSubItem = 0; //表示从第0列进行插入文本内容
memset(vItem.pszText, 0, 50); //初始化项内容空间
swprintf(vItem.pszText, L"List1Value%d", i); //在指定的项位置填充数据,哪种形式都可以
ListView_InsertItem(hWndListView, &vItem); //将项内容插到指定位置
vItem.iItem = i;//接下来重复操作,将第1,2,3列填充内容
vItem.iSubItem = 1;
memset(vItem.pszText, 0, 50);
swprintf(vItem.pszText, L"List2Value%d", i);
ListView_SetItem(hWndListView, &vItem); //第一次插入使用ListView_InsertItem,其余插入使用ListView_SetItem
vItem.iItem = i;
vItem.iSubItem = 2;
memset(vItem.pszText, 0, 50);
swprintf(vItem.pszText, L"List3Value%d", i);
ListView_SetItem(hWndListView, &vItem);
vItem.iItem = i;
vItem.iSubItem = 3;
memset(vItem.pszText, 0, 50);
wprintf(vItem.pszText, L"List4Value%d", i);
ListView_SetItem(hWndListView, &vItem);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
如图便是我们填充的结果
列表消息应用
列表中的消息处理在WM_NOTIFY中,是一个独立的消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
//此处创建列表
HWND hWndListView = CreateWindow(L"SysListView32", L"", LVS_REPORT | WS_CHILD |WS_VISIBLE | WS_BORDER, 10, 10, 400, 300, hWnd, (HMENU)IDC_LIST_COMM,((LPCREATESTRUCT)lParam)->hInstance, NULL);
//设置列表风格
LRESULT lStyle = SendMessage(hWndListView, LVM_GETEXTENDEDLISTVIEWSTYLE,NULL, NULL); //获取原有风格
lStyle |= (LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//注意或等
SendMessage(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, NULL, lStyle); //设置风格
//设置表头
LV_COLUMN lvc = { 0 }; //初始化LV_COLUMN表头结构,用来填充字符串
lvc.mask |= (LVCF_TEXT | LVCF_WIDTH); //mask设置标记,标记表头可以填充什么类型,此处为填充文本类型或图标
lvc.pszText = new WCHAR[50]; //开辟填充文本需要的空间
lvc.cx = 100; //设置列宽,即单个表头所占长度
memset(lvc.pszText, 0, 50); //初始化申请表头文本空间
memcpy(lvc.pszText, L"List1", 12);//在表头中填充字符串
//消息填写表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc); //发送插入列消息,在目标列表第0列插入表头
memset(lvc.pszText, 0, 50);//初始化表头
memcpy(lvc.pszText, L"List2", 12);//填充表头
SendMessage(hWndListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List3", 12);
SendMessage(hWndListView, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc);
memset(lvc.pszText, 0, 50);
memcpy(lvc.pszText, L"List4", 12);
//宏填写表头
ListView_InsertColumn(hWndListView, 3, &lvc); //利用宏的方式填充表头
//列表填充内容
LVITEM vItem = { 0 }; //初始化LVITEM项结构,该结构用于列表中填充文本
vItem.mask = LVIF_TEXT; //标记该项可填充文本
//表头设置了宽度后,项就不需要设置了
vItem.pszText = new WCHAR[50]; //开辟填充文本需要的空间
for (size_t i = 0; i < 10; i++)//通过循环每行每列都填充文本
{
vItem.iItem = i; //表示第几行进行插入文本内容
vItem.iSubItem = 0; //表示从第0列进行插入文本内容
memset(vItem.pszText, 0, 50); //初始化项内容空间
swprintf(vItem.pszText, L"List1Value%d", i); //在指定的项位置填充数据,哪种形式都可以
ListView_InsertItem(hWndListView, &vItem); //将项内容插到指定位置
vItem.iItem = i;//接下来重复操作,将第1,2,3列填充内容
vItem.iSubItem = 1;
memset(vItem.pszText, 0, 50);
swprintf(vItem.pszText, L"List2Value%d", i);
ListView_SetItem(hWndListView, &vItem); //首行插入使用ListView_InsertItem,其余插入使用ListView_SetItem
vItem.iItem = i;
vItem.iSubItem = 2;
memset(vItem.pszText, 0, 50);
swprintf(vItem.pszText, L"List3Value%d", i);
ListView_SetItem(hWndListView, &vItem);
vItem.iItem = i;
vItem.iSubItem = 3;
memset(vItem.pszText, 0, 50);
wprintf(vItem.pszText, L"List4Value%d", i);
ListView_SetItem(hWndListView, &vItem);
}
}
break;
case WM_NOTIFY: //处理列表消息
{
switch (((LPNMHDR)lParam)->code)//判断是否点击列表
{
case NM_CLICK: //左键点击列表弹窗内容
{
HWND hSWnd = GetDlgItem(hWnd, IDC_LIST_COMM); //获取列表句柄
DWORD dwItemIndex = ListView_GetSelectionMark(hSWnd); //获取当前点击的位置,行数索引
CHAR * szBuffer = new WCHAR[50]; //设置文本缓冲区
ListView_GetItemText(hSWnd, dwItemIndex, 2, szBuffer, 50); //将第二列的内容获取文本填充到缓冲区中
MessageBox(hWnd, szBuffer, L"Msg", MB_OK);//弹窗显示获取到的文本
break;
}
case NM_RCLICK: //右键点击列表删除选择行
{
HWND hSWnd = GetDlgItem(hWnd, IDC_LIST_COMM);//获取列表句柄
DWORD dwItemIndex = ListView_GetSelectionMark(hSWnd); //获取当前点击的位置,行数索引
SendMessage(hSWnd, LVM_DELETEITEM, dwItemIndex, NULL); //删除选择行
break;
}
default:
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}