|
(四)列表控制的应用技巧示例 本文给出具体实例演示列表控制及前面的表头控制和图像列表的应用技巧。步骤如下: 1、通过“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名为VCLIST的工程,在建立过程中选择基于对话框(Dialog based)的应用;将对话框中的默认控件删除,并将所有对话框属性中的Language域设置为Chinese(P.R.C.),以使应用程序支持中文; 建立两个图标IDI_GJ和IDI_XS,用来表示图标的选中和非选中状态,对于每个图标都应建立32X32和16X16两种大小,以保证程序的需要;
3、在对话框窗口中设计组合框(Group Box),组合框中设置四个无线按钮(Radio)“大图标|小图标|列表|资料”,同时设置排序、删除和关闭三个控制按钮(Button),并在对话框中设置大小合适的列表控制(List Ctrl),其对应标识分别如下: -------------------------------------------------------------------------------- 控制名称 标题名称 标识符号 --------------------------------------------------------------------------------
列表控制 IDC_LISTCTRL 组合框 方式 IDC_STATIC 无线按钮 大图标 IDC_STDICON 小图标 IDC_SMLICON 列 表 IDC_LIST 资 料 IDC_REPORT 按钮 排 序 IDC_SORT 删 除 IDC_DEL 关 闭 IDOK --------------------------------------------------------------------------------
4、在设置无线按钮时,需要注意的是只有大图标的Group属性为选中状态,而其它无线按钮的状态均为默认值。 5、选中列表控制控件,选择“VIEW->ClassWizard->Memory Variables”,并利用IDC_ LISTCTRL引入成员变量,其变量类型为: 变量名 种类 变量类型 m_ListCtrl Control ClistCtrl 同时利用“MESSAGES MAP”为各无线按钮和命令按钮增加控制功能。 6、然后在包含文件和代码文件中分别加入如下代码: (1)在VCLISTDlg.h中增加数据结构和定义 typedef struct tagSPS { //定义结构 char szPm[10]; //品名 int Lx; //0-GJ 1-XS char szSl[10]; //数量 char szDj[10]; //单价 char szJe[10]; //金额 } SPS; int CALLBACK CompareFunc(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort); |
(2)在VCLISTDlg.CPP中的起始处增加初始化数据和程序定义 //在文件开始处增加数据结构初始化 SPS Sps[]={//信息 {"红梅",0,"1000","30","30000"}, {"黄梅",0,"1000","29","29000"}, {"绿梅",0,"1000","28","28000"}, {"青梅",0,"1000","27","27000"}, {"白梅",0,"1000","31","31000"}, {"红梅",1,"1000","30","30000"}, {"黄梅",1,"1000","29","29000"}, {"绿梅",1,"1000","28","28000"}, {"青梅",1,"1000","27","27000"}, {"白梅",1,"1000","31","31000"}}; CImageList Cil1,Cil2;//大小图像列表 |
(3)在程序初始化处增加表头、图像和列表控制建立代码 BOOL CVCLISTDlg::OnInitDialog() {CDialog::OnInitDialog(); //......//其它代码 // TODO: Add extra initialization here此处增加代码 LV_ITEM lvitem; LV_COLUMN lvcol; int i,iPos,iItemNum; CVCLISTApp *pApp=(CVCLISTApp *)AfxGetApp();//创建图象列表 Cil1.Create(32,32,TRUE,2,2); Cil1.Add(pApp->LoadIcon(IDI_GJ)); Cil1.Add(pApp->LoadIcon(IDI_XS)); Cil2.Create(16,16,TRUE,2,2); Cil2.Add(pApp->LoadIcon(IDI_GJ)); Cil2.Add(pApp->LoadIcon(IDI_XS));//设置图象列表 m_ListCtrl.SetImageList(&Cil1,LVSIL_NORMAL); m_ListCtrl.SetImageList(&Cil2,LVSIL_SMALL);//向列表控制中添加表列 lvcol.mask=LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH; lvcol.fmt=LVCFMT_CENTER;//居中 i=0; lvcol.pszText="品 名"; lvcol.iSubItem=i; lvcol.cx=70; m_ListCtrl.InsertColumn(i++,&lvcol); lvcol.pszText="数 量"; lvcol.iSubItem=i; lvcol.cx=70; m_ListCtrl.InsertColumn(i++,&lvcol); lvcol.pszText="单 价"; lvcol.iSubItem=i; lvcol.cx=70; m_ListCtrl.InsertColumn(i++,&lvcol); lvcol.pszText="金 额"; lvcol.iSubItem=i; lvcol.cx=70; m_ListCtrl.InsertColumn(i++,&lvcol); //向列表控制中添加表项 iItemNum=sizeof(Sps)/sizeof(SPS); for(i=0;i<iItemNum;i++){ lvitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM; lvitem.iItem=i; lvitem.iSubItem=0; lvitem.pszText=Sps[i].szPm; lvitem.iImage=Sps[i].Lx; lvitem.lParam=i; iPos=m_ListCtrl.InsertItem(&lvitem);//返回表项插入后的索引号 lvitem.mask=LVIF_TEXT; lvitem.iItem=iPos; lvitem.iSubItem=1; lvitem.pszText=Sps[i].szSl; m_ListCtrl.SetItem(&lvitem); lvitem.iSubItem=2; lvitem.pszText=Sps[i].szDj; m_ListCtrl.SetItem(&lvitem); lvitem.iSubItem=3; lvitem.pszText=Sps[i].szJe; m_ListCtrl.SetItem(&lvitem); } CheckRadioButton(IDC_STDICON,IDC_REPORT,IDC_STDICON); return TRUE; // return TRUE unless you set the focus to a control } |
(4)完善列表显示方式代码 在利用Classwizard类向导创建各功能按钮显示功能函数之后,必须依次完善这些功能函数的代码,这些功能函数如下: void CVCLISTDlg::OnStdicon()//设置大图标显示方式 { // TODO: Add your control notification handler code here LONG lStyle; lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//获取当前窗口类型 lStyle&=~LVS_TYPEMASK; //清除显示方式位 lStyle|=LVS_ICON; //设置显示方式 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//设置窗口类型 } void CVCLISTDlg::OnSmlicon() //设置小图标显示方式 { // TODO: Add your control notification handler code here LONG lStyle; lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//获取当前窗口类型 lStyle&=~LVS_TYPEMASK; //清除显示方式位 lStyle|=LVS_SMALLICON; //设置显示方式 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//设置窗口类型 } void CVCLISTDlg::OnList() //设置列表显示方式 { // TODO: Add your control notification handler code here LONG lStyle; lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//获取当前窗口类型 lStyle&=~LVS_TYPEMASK; //清除显示方式位 lStyle|=LVS_LIST; //设置显示方式 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//设置窗口类型 } void CVCLISTDlg::OnReport() //详细资料显示方式 { // TODO: Add your control notification handler code here LONG lStyle; lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//获取当前窗口类型 lStyle&=~LVS_TYPEMASK; //清除显示方式位 lStyle|=LVS_REPORT; //设置显示方式 SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//设置窗口类型 } |
(5)删除功能的实现 要实现删除功能,必须取得选中表项的数和表项总数,并且需要从后向前进行依次删除,其原因是每个表项被删除后,其后各表项的索引号均会发生递减变化,如果采取从前向后删除的方法,就会造成无法正常删除选中的表项,其功能代码如下: void CVCLISTDlg::OnDel() //删除按钮功能 { // TODO: Add your control notification handler code here int i,iState; int nItemSelected=m_ListCtrl.GetSelectedCount();//所选表项数 int nItemCount=m_ListCtrl.GetItemCount();//表项总数 if(nItemSelected<1) return; for(i=nItemCount-1;i>=0;i--){ iState=m_ListCtrl.GetItemState(i,LVIS_SELECTED); if(iState!=0) m_ListCtrl.DeleteItem(i); } } |
(6)排序功能的实现 列表控制有一个特殊的功能,当以详细资料方式显示时,列表顶部的表头可以当作按钮来使用,这可以通过列表控制创建时的风格来控制。当鼠标点击列表头名称时,列表控制就会向其父窗口发送一个LNV_COLUMNCLICK消息,利用类导向中列表控制IDC_LISTCTRL对应的LNV_COLUMNCLICK消息加入相应处理函数,就可将表列按照特定顺序进行排列。其函数使用方法见程序,其中iSort为排序的表列索引号,(PFNLVCOMPARE)CompareFunc为进行具体排序的回调函数,也就是说,通过鼠标点击表头实现的排序过程是由第三方开发的专用排序函数来实现的,排序函数只是实现表项的具体比较操作,而整个排序过程是由SortItemS属性通过不断调用这个函数来实现的。正常的排序过程是升序方式,通过调换排序函数中的参数值,就可实现降序排列,即将PARAM1与PARAM2调换位置。这个回调函数的前两个参数为表列中表项的索引号,第三个参数为排序的表列索引号。 void CVCLISTDlg::OnColumnclickListctrl(NMHDR* pNMHDR, LRESULT* pResult) { //鼠标左键单击表头处理函数 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here static int iSorted=-1;//排列序号 if (pNMListView->iSubItem==iSorted) return; iSorted=pNMListView->iSubItem; m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,iSorted); *pResult = 0; } //排序时比较表项的回调函数 int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort) { char *text1,*text2; switch (lParamSort){ case 0L:text1=Sps[lParam1].szPm; text2=Sps[lParam2].szPm;break; case 1L:text1=Sps[lParam1].szSl; text2=Sps[lParam2].szSl;break; case 2L:text1=Sps[lParam1].szDj; text2=Sps[lParam2].szDj;break; case 3L:text1=Sps[lParam1].szJe; text2=Sps[lParam2].szJe;break; } return (strcmp(text1,text2));//结果为>0 =0 <0 } |
同样,也可以通过专用按钮来实现排序功能,如本文的排序按钮对应的功能代码如下: void CVCLISTDlg::OnSort() { // TODO: Add your control notification handler code here m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,0);} |
7、列表视的演练技巧 在使用列表视时,其方法与列表控制基本相同,只不过列表视是在窗口中来实现的而列表控制是在对话框中实现,列表视的各种功能是通过菜单来实现的而列表控制是通过按钮等方式来实现的,列表控制需要在对话框中创建列表控制控件而列表视直接占据整个窗口,在设计过程中只要将按钮和列表控制设计过程变为菜单设计,并注意在功能增加是在类向导中是通过菜单命令来操作,同时在每个功能函数前面增加取得列表视引用的命令( CListCtrl& ListCtrl = GetListCtrl()),而其余数据结构和代码均不需要修改,实现起来比较容易。 |