以下未经说明,listctrl默认view 风格为report 1. CListCtrl 风格 LVS_ICON: 为每个item显示大图标 LVS_SMALLICON: 为每个item显示小图标 LVS_LIST: 显示一列带有小图标的item LVS_REPORT: 显示item详细资料 直观的理解:windows资源管理器,“查看”标签下的“大图标,小图标,列表,详细资料” 2. 设置listctrl 风格及扩展风格 LONG lStyle; lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style lStyle &= ~LVS_TYPEMASK; //清除显示方式位 lStyle |= LVS_REPORT; //设置style SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style DWORD dwStyle = m_list.GetExtendedStyle(); dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl) dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl) dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件 m_list.SetExtendedStyle(dwStyle); //设置扩展风格 注:listview的style请查阅msdn http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp 3. 插入数据 m_list.InsertColumn( 0, "ID", LVCFMT_LEFT, 40 );//插入列 m_list.InsertColumn( 1, "NAME", LVCFMT_LEFT, 50 ); int nRow = m_list.InsertItem(0, “11”);//插入行 m_list.SetItemText(nRow, 1, “jacky”);//设置数据 4. 一直选中item 选中style中的Show selection always,或者在上面第2点中设置LVS_SHOWSELALWAYS 5. 选中和取消选中一行 int nIndex = 0; //选中 m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); //取消选中 m_list.SetItemState(nIndex, 0, LVIS_SELECTED|LVIS_FOCUSED); 6. 得到listctrl中所有行的checkbox的状态 m_list.SetExtendedStyle(LVS_EX_CHECKBOXES); CString str; for(int i=0; i<m_list.GetItemCount(); i++) { if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED || m_list.GetCheck(i)) { str.Format(_T("第%d行的checkbox为选中状态"), i); AfxMessageBox(str); } } 7. 得到listctrl中所有选中行的序号 方法一: CString str; for(int i=0; i<m_list.GetItemCount(); i++) { if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED ) { str.Format(_T("选中了第%d行"), i); AfxMessageBox(str); } } 方法二: POSITION pos = m_list.GetFirstSelectedItemPosition(); if (pos == NULL) TRACE0("No items were selected!/n"); else { while (pos) { int nItem = m_list.GetNextSelectedItem(pos); TRACE1("Item %d was selected!/n", nItem); // you could do your own processing on nItem here } } 8. 得到item的信息 TCHAR szBuf[1024]; LVITEM lvi; lvi.iItem = nItemIndex; lvi.iSubItem = 0; lvi.mask = LVIF_TEXT; lvi.pszText = szBuf; lvi.cchTextMax = 1024; m_list.GetItem(&lvi); 关于得到设置item的状态,还可以参考msdn文章 Q173242: Use Masks to Set/Get Item States in CListCtrl http://support.microsoft.com/kb/173242/en-us 9. 得到listctrl的所有列的header字符串内容 LVCOLUMN lvcol; char str[256]; int nColNum; CString strColumnName[4];//假如有4列 nColNum = 0; lvcol.mask = LVCF_TEXT; lvcol.pszText = str; lvcol.cchTextMax = 256; while(m_list.GetColumn(nColNum, &lvcol)) { strColumnName[nColNum] = lvcol.pszText; nColNum++; } 10. 使listctrl中一项可见,即滚动滚动条 m_list.EnsureVisible(i, FALSE); 11. 得到listctrl列数 int nHeadNum = m_list.GetHeaderCtrl()->GetItemCount(); 12. 删除所有列 方法一: while ( m_list.DeleteColumn (0)) 因为你删除了第一列后,后面的列会依次向上移动。 方法二: int nColumns = 4; for (int i=nColumns-1; i>=0; i--) m_list.DeleteColumn (i); 13. 得到单击的listctrl的行列号 添加listctrl控件的NM_CLICK消息相应函数 void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) { // 方法一: /* DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_list.ScreenToClient(&point); LVHITTESTINFO lvinfo; lvinfo.pt = point; lvinfo.flags = LVHT_ABOVE; int nItem = m_list.SubItemHitTest(&lvinfo); if(nItem != -1) { CString strtemp; strtemp.Format("单击的是第%d行第%d列", lvinfo.iItem, lvinfo.iSubItem); AfxMessageBox(strtemp); } */ // 方法二: /* NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { CString strtemp; strtemp.Format("单击的是第%d行第%d列", pNMListView->iItem, pNMListView->iSubItem); AfxMessageBox(strtemp); } */ *pResult = 0; } 14. 判断是否点击在listctrl的checkbox上 添加listctrl控件的NM_CLICK消息相应函数 void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) { DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_list.ScreenToClient(&point); LVHITTESTINFO lvinfo; lvinfo.pt = point; lvinfo.flags = LVHT_ABOVE; UINT nFlag; int nItem = m_list.HitTest(point, &nFlag); //判断是否点在checkbox上 if(nFlag == LVHT_ONITEMSTATEICON) { AfxMessageBox("点在listctrl的checkbox上"); } *pResult = 0; } 15. 右键点击listctrl的item弹出菜单 添加listctrl控件的NM_RCLICK消息相应函数 void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); CMenu menu; VERIFY( menu.LoadMenu( IDR_MENU1 ) ); CMenu* popup = menu.GetSubMenu(0); ASSERT( popup != NULL ); popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ); } *pResult = 0; }
c++:list control的用法 ListControl列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ); 创建一个窗口,dwStyle中可以使用以下一些列表控件的专用风格: LVS_ICON ,LVS_SMALLICON ,LVS_LIST, LVS_REPORT 这四种风格决定控件的外观,同时只可以选择其中一种,分别对应:大图标显示,小图标显示,列表显示,详细报表显示 ..。 LVS_EDITLABELS 结点的显示字符可以被编辑,对于报表风格来讲可编辑的只为第一列。 LVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点 LVS_SINGLESEL 同时只能选中列表中一项 首先你需要设置列表控件所使用的ImageList,如果你使用大图标显示风格,你就需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL); 如果使用其它三种风格显示而不想显示图标你可以不进行任何设置,否则需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL); int InsertItem( int nItem, LPCTSTR lpszItem ); 插入行 nItem:指明插入位置 lpszItem:为显示字符。 除LVS_REPORT风格外其他三种风格都只需要直接调用InsertItem就可以了,但如果使用报表风格就必须先设置列表控件中的列信息。 int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);插入列 iCol:为列的位置,从零开始 lpszColumnHeading:为显示的列名 nFormat:为显示对齐方式 nWidth:为显示宽度 nSubItem:为分配给该列的列索引。 BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );设置每列的显示字符 nItem:为行位置 nSubItem:为列位置 lpszText:为显示字符 下面的代码演示了如何设置多列并插入数据: m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//设置ImageList m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//设置列 m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1); m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2); m_list.InsertItem(0,"Item 1_1");//插入行 m_list.SetItemText(0,1,"Item 1_2");//设置该行的不同列的显示字符 m_list.SetItemText(0,2,"Item 1_3") COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr ):用于得到/设置显示的字符颜色。 COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr ):用于得到/设置显示的背景颜色。 void SetItemCount( int iCount ):用于得到添加进列表中项的数量。 BOOL DeleteItem(int nItem):用于删除某一项 BOOL DeleteAllItems( ):将删除所有项。 BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent):用于设置背景位图。 CString GetItemText( int nItem, int nSubItem ):用于得到某项的显示字符。 列表控件的消息映射同样使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于列表控件可能取值和对应的数据结构为: LVN_BEGINLABELEDIT 在开始某项编辑字符时发送,所用结构: NMLVDISPINFO LVN_ENDLABELEDIT 在结束某项编辑字符时发送,所用结构: NMLVDISPINFO LVN_GETDISPINFO 在需要得到某项信息时发送,(如得到某项的显示字符)所用结构:NMLVDISPINFO 关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。 关于动态提供结点所显示的字符:首先你在项时需要指明lpszItem参数为: LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为 LPNMLVDISPINFO,然后填充其中item.pszText。通过item中的iItem,iSubItem可以知道当前显示的为那一项。下面的代码演示了这种方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点 m_list.InsertItem(LPSTR_TEXTCALLBACK,...) m_list.InsertItem(LPSTR_TEXTCALLBACK,...) //处理消息 void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; pLVDI->item.pszText=szOut[pTVDI->item.iItem]; //通过iItem得到需要显示的字符在数组中的位置 *pResult = 0; } 关于编辑某项的显示字符:(在报表风格中只对第一列有效)首先需要设置列表控件的LVS_EDITLABELS风格,在开始编辑时该控件将会发送 LVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送LVN_ENDLABELEDIT,在处理该消息时需要将参数 pNMHDR转换为LPNMLVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.iItem==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText); //重置显示字符 *pResult = 0; } 上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。 如何得到当前选中项位置:在列表控件中没有一个类似于ListBox中GetCurSel()的函数,但是可以通过调用GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);得到选中项位置。 list control控件中的风格选项: m_list1.SetExtendedStyle( LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES ); LVS_EX_FULLROWSELECT表示可以点中行中的任意一个列选中这一条记录 LVS_EX_GRIDLINES表示列之间有分隔符号 LVS_EX_CHECKBOXES 表示每一行第一列是checkbox LVCOLUMN:listviewcolumn 设置表头 lvColumn.mask = LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH|LVCF_FMT; 设置表头风格 lvColumn.fmt = LVCFMT_CENTER; 设置表头对齐方式 lvColumn.iSubItem = i; 表头列序 lvColumn.pszText = HeaderTxt[i]; 表头名称 lvColumn.cx = 90; 表头宽度 m_list.InsertColumn(i,&lvColumn); 插入列 list control 本文全面介绍了如何编辑List Control里面的任何子项 介绍 内容有点多,译出来也没多大意思,大致就是说一个VC程序员会常常碰到List Control,List Control有很多方法可以显示数据,可List Control里默认的没有编辑功能,故在此智短文里,那个牛叉的人教你怎么实现这个功能。这篇文章是基于VC MFC滴,用别的功具的娃们当然也可以看看,呵呵,不多说,先实现图上ok exit两个按钮: void CMultipleColumnsDlg::OK() { CDialog::EndDialog (0); // Add this line } void CMultipleColumnsDlg::OnExit() { CDialog::EndDialog (0); // Add this line } 接下来添加一个ListCtrl控件,记得把ListCtrl的style设置成Report,这个是为了实现我们要多行显示的功能 然后增加一个文本框Edit Box去掉它的Border style属性 增加一个InsertItems() 成员函数,用来写入ListControl的显示内容 void CMultipleColumnsDlg::InsertItems() { HWND hWnd = ::GetDlgItem(m_hWnd, IDC_LIST1); // Set the LVCOLUMN structure with the required // column information LVCOLUMN list; list.mask = LVCF_TEXT |LVCF_WIDTH| LVCF_FMT |LVCF_SUBITEM; list.fmt = LVCFMT_LEFT; list.cx = 50; list.pszText = "S.No"; list.iSubItem = 0; //Inserts the column ::SendMessage(hWnd,LVM_INSERTCOLUMN, (WPARAM)0,(WPARAM)&list); list.cx = 100; list.pszText = "Name"; list.iSubItem = 1; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, (WPARAM)1,(WPARAM)&list); list.cx = 100; list.pszText = "Address"; list.iSubItem = 2; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, (WPARAM)1,(WPARAM)&list); list.cx = 100; list.pszText = "Country"; list.iSubItem = 2; ::SendMessage(hWnd ,LVM_INSERTCOLUMN, (WPARAM)1,(WPARAM)&list); // Inserts first Row with four columns 插入行 SetCell(hWnd,"1",0,0); SetCell(hWnd,"Prabhakar",0,1); SetCell(hWnd,"Hyderabad",0,2); SetCell(hWnd,"India",0,3); // Inserts second Row with four columns . SetCell(hWnd,"2",1,0); SetCell(hWnd,"Uday",1,1); SetCell(hWnd,"Chennai",1,2); SetCell(hWnd,"India",1,3); } 自定义的SetCell( ) 函数,用来实现插入数据用的 void CMultipleColumnsDlg::SetCell(HWND hWnd1, CString value, int nRow, int nCol) { TCHAR szString [256]; wsprintf(szString,value ,0); //Fill the LVITEM structure with the //values given as parameters. LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = nRow; lvItem.pszText = szString; lvItem.iSubItem = nCol; if(nCol >0) //set the value of listItem ::SendMessage(hWnd1,LVM_SETITEM, (WPARAM)0,(WPARAM)&lvItem); else //Insert the value into List ListView_InsertItem(hWnd1,&lvItem); } //通过行和列得到项目里面的数据 CString CMultipleColumnsDlg::GetItemText( HWND hWnd, int nItem, int nSubItem) const { LVITEM lvi; memset(&lvi, 0, sizeof(LVITEM)); lvi.iSubItem = nSubItem; CString str; int nLen = 128; int nRes; do { nLen *= 2; lvi.cchTextMax = nLen; lvi.pszText = str.GetBufferSetLength(nLen); nRes = (int)::SendMessage(hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); str.ReleaseBuffer(); return str; } } //为窗口类添加两个成员变量: int nItem, nSubItem; 用Class wizard 添加 NM_CLICK 响应 ,当用户点击任何位置时,就会对应出现一个Edit Box,并可以修改数据 void CMultipleColumnsDlg::OnClickList( NMHDR* pNMHDR, LRESULT* pResult) { Invalidate(); HWND hWnd1 = ::GetDlgItem (m_hWnd,IDC_LIST1); LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE) pNMHDR; RECT rect; //get the row number nItem = temp->iItem; //get the column number nSubItem = temp->iSubItem; if(nSubItem == 0 || nSubItem == -1 || nItem == -1) return ; //Retrieve the text of the selected subItem //from the list CString str = GetItemText(hWnd1,nItem , nSubItem); RECT rect1,rect2; // this macro is used to retrieve the Rectanle // of the selected SubItem ListView_GetSubItemRect(hWnd1,temp->iItem, temp->iSubItem,LVIR_BOUNDS,&rect); //Get the Rectange of the listControl ::GetWindowRect(temp->hdr.hwndFrom,&rect1); //Get the Rectange of the Dialog ::GetWindowRect(m_hWnd,&rect2); int x=rect1.left-rect2.left; int y=rect1.top-rect2.top; if(nItem != -1) ::SetWindowPos(::GetDlgItem(m_hWnd,IDC_EDIT1), HWND_TOP,rect.left+x,rect.top+4, rect.right-rect.left - 3, rect.bottom-rect.top -1,NULL); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1),SW_SHOW); ::SetFocus(::GetDlgItem(m_hWnd,IDC_EDIT1)); //Draw a Rectangle around the SubItem ::Rectangle(::GetDC(temp->hdr.hwndFrom), rect.left,rect.top-1,rect.right,rect.bottom); //Set the listItem text in the EditBox ::SetWindowText(::GetDlgItem(m_hWnd,IDC_EDIT1),str); *pResult = 0; } To handle the ENTER key we need to write the virtual function OnOk (响应ENTER键) afx_msg void OnOK(); In MultipleColumnsDlg.cpp write the following code. // This function handles the ENTER key void CMultipleColumnsDlg::OnOK() { CWnd* pwndCtrl = GetFocus(); // get the control ID which is // presently having the focus int ctrl_ID = pwndCtrl->GetDlgCtrlID(); CString str; switch (ctrl_ID) { //if the control is the EditBox case IDC_EDIT1: //get the text from the EditBox GetDlgItemText(IDC_EDIT1,str); //set the value in the listContorl with the //specified Item & SubItem values SetCell(::GetDlgItem (m_hWnd,IDC_LIST1), str,nItem,nSubItem); ::SendDlgItemMessage(m_hWnd,IDC_EDIT1, WM_KILLFOCUS,0,0); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1), SW_HIDE); break; default: break; } } 最后一步在OnInitDialog 中设置List Control的样式 ListView_SetExtendedListViewStyle(::GetDlgItem (m_hWnd,IDC_LIST1),LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); InsertItems(); ::ShowWindow(::GetDlgItem(m_hWnd,IDC_EDIT1),SW_HIDE);
1。先来介绍REPORT类型的 CListCtrl: 首先使用下面的语句设置CListCtrl的style: DWORD SetExtendedStyle( DWORD dwNewStyle ); 其中 LVS_EX_CHECKBOXES 表 示添加CheckBox LVS_EX_FULLROWSELECT 表示选择整行 LVS_EX_GRIDLINES 表示添加表格线 如果设置了LVS_EX_CHECKBOXES属性,则可以用 BOOL GetCheck( int nItem ) const; 来得到某一行是否Checked。 可以先用下面的语句来删除以前的东西: for(int k=2;k>=0;k--) //注意要从后往前删,否则出错 m_ListCtrl.DeleteColumn(k); m_ListCtrl.DeleteAllItems(); 用下面的语句新建列: m_ListCtrl.InsertColumn(0,_T(" 文件名"),LVCFMT_IMAGE|LVCFMT_LEFT); m_ListCtrl.InsertColumn(1,_T("仪器类别")); m_ListCtrl.InsertColumn(2,_T("项目类别")); 其中 LVCFMT_IMAGE表示可以在第一列加入图标。如果不要图标可以删去。 然后设置列宽: for(j=0;j<3;j++) m_ListCtrl.SetColumnWidth(j ,100); 以下为列表加入图标,如果不需要图标,可以跳过这一步。注意只在第一次加入,如果多次加入会出错! 先 在头文件中加入声明: CImageList m_ImageList; 这是必要的,如果在cpp的某个函数中加入由于生命期结束,CImageList自动释放,则效果是列表中看不到图标,只看到一个白方块。 下面生成 CImageList,并将其绑定到CListCtrl中,这是CImageList中还没有图标,只是一个容器: static int flag=2; if(flag==2){//只调用一次SetImageList,否 则出错 m_ImageList.Create(128, 128, ILC_COLORDDB|ILC_MASK, 20, 1); m_ListCtrl.SetImageList(&m_ImageList,LVSIL_SMALL); } flag=(flag+1)%2; 如果CListCtrl已经用过,曾经加过图标进去,这时就要删除上次放进m_ImageList中的Image for(int kk=0;kk<m_ImageList.GetImageCount();kk++) m_ImageList.Remove(k); 下面介绍如何向CListCtrl里面加入行,并同时为每一行动态加入图标: 假设m_listRowCount 为要加入的行数。 CBitmap* bitmap; bitmap=new CBitmap[m_list1rowCount]; HBITMAP hbitmap; for(int i = 0; i < m_listRowCount; i++) { //为每一行插入相应的缩略图 CFile f; CFileException e; if( !f.Open(m_FileName, CFile::modeRead, &e )){ //m_FileName为bmp文件名,由你来定 hbitmap = (HBITMAP)LoadImage(NULL,path+"blank.bmp",IMAGE_BITMAP,0,0, LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE); }else{ f.Close(); hbitmap = (HBITMAP)LoadImage(NULL,bmpFile,IMAGE_BITMAP,0,0, LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE); } bitmap[i].Attach(hbitmap); m_ImageList.Add(&bitmap[i], RGB(0, 128, 128)); //插入行 m_ListCtrl.InsertItem(i,m_FileName,i); m_ListCtrl.SetItemText(i,1,type); m_ListCtrl.SetItemText(i,2,m_Path); } // 记得删除已经没用的临时文件 if(m_list1rowCount!=0) delete[] bitmap; 2。如果是ICON类型的CListCtrl,则要做一点点改动: 把绑定图标集的代码由 SetImageList(&m_ImageList,LVSIL_SMALL); 改为 SetImageList(&m_ImageList,LVSIL_NORMAL); 插入行时只用 InsertItem(i,mainSet.m_FileName,i); 不 用 SetItemText(i,1,type); 之类的代码。 设置报表的样式 选中一整行: m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_FULLROWSELECT); 绘 制表格: m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_GRIDLINES); 带 复选框: m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_CHECKBOXES); 自 动切换: m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_TRACKSELECT); 选 定一行: 设置CListCtrl的Show selection always选项 SetItemState (iIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED) 选中一个或多个项目时,会发送LVN_ITEMCHANGED消息,可以使用 GetSelectedCount()方法得到被选定的项的数目。 点击列头的 消息响应: ON_NOTIFY(HDN_ITEMCLICKW, 0, ResponseFunc) 消息,需要自己添加 或者: ON_NOTIFY(LVN_COLUMNCLICK, ID_yourCtrl, ResponseFunc)//向导添加 前者后响应,后者先响应 响应函数: ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult) 双击CListCtrl中的ITEM的消息是及消息函数: ON_NOTIFY(NM_DBLCLK, ID_yourCtrl, ResponseFunc) 单击ITEM的消息响应: ON_NOTIFY(NM_CLICK, ID_yourCtrl, ResponseFunc) ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult) HDN_ITEMCLICK 就是Header control Notify message for mouse left click on the Header control! 而HDN_ITEMCLICK是当List View中存在一个Header Contrl时,Header Ctrl通知父窗口List View的! CListCtrl中的Item被选中触发LBN_SELCHANGE(通过WM_COMMAND)消息! 删除CListCtrl中选定的项: POSITION pos; int nIndex; for(; pos= GetFirstSelectedItemPosition();) { nIndex = GetNextSelectedItem(pos); DeleteItem(nIndex); } 在ListCtrl中进行排序 列表控件(CListCtrl)的顶部有一排按钮,用户可以通过选择不同的列来对记录进行排序。但是 CListCtrl并没有自动排序的功能,我们需要自己添加一个用于排序的回调函数来比较两个数据的大小,此外还需要响应排序按钮被点击的消息。下面讲述一下具体的做法。 CListCtrl提供了用于排序的函数,函数原型为:BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData )。其中第一个参数为全局排序函数的地址,第二个参数为用户数据,你可以根据你的需要传递一个数据或是指针。该函数返回-1代表第一项排应在第二项前面,返回1代表第一项排应在第二项后面,返回0代表两项相等。 用于排序的函数原形为:int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort),其中第三个参数为调用者传递的数据(即调用SortItems时的第二个参数dwData)。第一和第二个参数为用于比较的两项的ItemData,你可以通过DWORD CListCtrl::GetItemData( int nItem )/BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )来对每一项的ItemData进行存取。在添加项时选用特定的CListCtrl::InsertItem也可以设置该值。由于你在排序时只能通过该值来确定项的位置所以你应该比较明确的确定该值的含义。 最后一点,我们需要知道什么时候需要排序,实现这点可以在父窗口中对 LVN_COLUMNCLICK消息进行处理来实现。 下面我们看一个例子,这个例子是一个派生类,并支持顺序/倒序两种方式排序。为了简单我对全局数据进行排序,而在实际应用中会有多组需要排序的数据,所以需要通过传递参数的方式来告诉派序函数需要对什么数据进行排序。 //全局数据 struct DEMO_DATA { char szName[20]; int iAge; }strAllData[5]={{" 王某",30},{"张某",40},{"武某",32},{"陈某",20},{"李某",36}}; //CListCtrl派生类定义 class CSortList : public CListCtrl { // Construction public: CSortList(); BOOL m_fAsc;//是否顺序排序 int m_nSortedCol;//当前排序的列 protected: //{{AFX_MSG(CSortList) //}}AFX_MSG ... }; // 父窗口中包含该CListCtrl派生类对象 class CSort_in_list_ctrlDlg : public CDialog { // Construction public: CSort_in_list_ctrlDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CSort_in_list_ctrlDlg) enum { IDD = IDD_SORT_IN_LIST_CTRL_DIALOG }; CSortList m_listTest; //}}AFX_DATA } // 在父窗口中定义LVN_COLUMNCLICK消息映射 BEGIN_MESSAGE_MAP(CSort_in_list_ctrlDlg, CDialog) //{{AFX_MSG_MAP(CSort_in_list_ctrlDlg) ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1) //}}AFX_MSG_MAP END_MESSAGE_MAP() // 初始化数据 BOOL CSort_in_list_ctrlDlg::OnInitDialog() { CDialog::OnInitDialog(); // 初始化ListCtrl中数据列表 m_listTest.InsertColumn(0,"姓名"); m_listTest.InsertColumn(1," 年龄"); m_listTest.SetColumnWidth(0,80); m_listTest.SetColumnWidth(1,80); for(int i=0;i<5;i++) { m_listTest.InsertItem(i,strAllData[i].szName); char szAge[10]; sprintf(szAge,"%d",strAllData[i].iAge); m_listTest.SetItemText(i,1,szAge); // 设置每项的ItemData为数组中数据的索引 //在排序函数中通过该ItemData来确定数据 m_listTest.SetItemData(i,i); } return TRUE; // return TRUE unless you set the focus to a control } // 处理消息 void CSort_in_list_ctrlDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; //设置排序方式 if( pNMListView->iSubItem == m_listTest.m_nSortedCol ) m_listTest.m_fAsc = !m_listTest.m_fAsc; else { m_listTest.m_fAsc = TRUE; m_listTest.m_nSortedCol = pNMListView->iSubItem; } // 调用排序函数 m_listTest.SortItems( ListCompare, (DWORD)&m_listTest ); *pResult = 0; } //排序函数实现 int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { // 通过传递的参数来得到CSortList对象指针,从而得到排序方式 CSortList* pV=(CSortList*)lParamSort; //通过ItemData来确定数据 DEMO_DATA* pInfo1=strAllData+lParam1; DEMO_DATA* pInfo2=strAllData+lParam2; CString szComp1,szComp2; int iCompRes; switch(pV->m_nSortedCol) { case(0): // 以第一列为根据排序 szComp1=pInfo1->szName; szComp2=pInfo2->szName; iCompRes=szComp1.Compare(szComp2); break; case(1): // 以第二列为根据排序 if(pInfo1->iAge == pInfo2->iAge) iCompRes = 0; else iCompRes=(pInfo1->iAge < pInfo2->iAge)?-1:1; break; default: ASSERT(0); break; } // 根据当前的排序方式进行调整 if(pV->m_fAsc) return iCompRes; else return iCompRes*-1; } 排序最快: CListCtrl::SortItems Example // Sort the item in reverse alphabetical order. static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { // lParamSort contains a pointer to the list view control. // The lParam of an item is just its index. CListCtrl* pListCtrl = (CListCtrl*) lParamSort; CString strItem1 = pListCtrl->GetItemText(lParam1, 0); CString strItem2 = pListCtrl->GetItemText(lParam2, 0); return strcmp(strItem2, strItem1); } void snip_CListCtrl_SortItems() { // The pointer to my list view control. extern CListCtrl* pmyListCtrl; // Sort the list view items using my callback procedure. pmyListCtrl->SortItems(MyCompareProc, (LPARAM) pmyListCtrl); } If you don’t want to allow the users to sort the list by clicking on the header, you can use the style LVS_NOSORTHEADER. However, if you do want to allow sorting, you do not specify the LVS_NOSORTHEADER. The control, though, does not sort the items. You have to handle the HDN_ITEMCLICK notification from the header control and process it appropriately. In the code below, we have used the sorting function SortTextItems() developed in a previous section. You may choose to sort the items in a different manner. Step 1: Add two member variables Add two member variables to the CListCtrl. The first variable to track which column has been sorted on, if any. The second variable to track if the sort is ascending or descending. int nSortedCol; BOOL bSortAscending; Step 2: Initialize them in the constructor. Initialize nSortedCol to -1 to indicate that no column has been sorted on. If the list is initially sorted, then this variable should reflect that. nSortedCol = -1; bSortAscending = TRUE; Step 3: Add entry in message map to handle HDN_ITEMCLICK Actually you need to add two entries. For HDN_ITEMCLICKA and HDN_ITEMCLICKW. Do not use the class wizard to add the entry. For one, you need to add two entries whereas the class wizard will allow you only one. Secondly, the class wizard uses the wrong macro in the entry. It uses ON_NOTIFY_REFLECT() instead of ON_NOTIFY(). Since the HDN_ITEMCLICK is a notification from the header control to the list view control, it is a direct notification and not a reflected one. ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked) ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked) Note that we specify the same function for both the notification. Actually the program will receive one or the other and not both. What notification it receives will depend on the OS. The list view control on Windows 95 will send the ANSI version and the control on NT will send the UNICODE version. Also, note that the second argument is zero. This value filters for the id of the control and we know that header control id is zero. Step 4: Write the OnHeaderClicked() function Here’s where you decide what to do when the user clicks on a column header. The expected behaviour is to sort the list based on the values of the items in that column. In this function we have used the SortTextItems() function developed in a previous section. If any of the columns displays numeric or date values, then you would have to provide custom sorting for them. void CMyListCtrl::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult) { HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR; if( phdn->iButton == 0 ) { // User clicked on header using left mouse button if( phdn->iItem == nSortedCol ) bSortAscending = !bSortAscending; else bSortAscending = TRUE; nSortedCol = phdn->iItem; SortTextItems( nSortedCol, bSortAscending ); } *pResult = 0; } 让CListCtrl的SubItem也具有编辑功能: 要重载一个文本框,然后在 LVN_BEGINLABELEDIT时改变文本框位置。 CInEdit m_InEdit; if( ( GetStyle() & LVS_TYPEMASK ) == LVS_REPORT && ( m_nEditSubItem != 0 ) ) { HWND hwndEdit; CRect rtBound; CString strText; hwndEdit = (HWND)SendMessage( LVM_GETEDITCONTROL ); GetSubItemRect( pDispInfo->item.iItem, m_nEditSubItem, LVIR_LABEL, rtBound ); m_InEdit.SubclassWindow( hwndEdit ); m_InEdit.m_left = rtBound.left; strText = GetItemText( pDispInfo->item.iItem, m_nEditSubItem ); m_InEdit.SetWindowText( strText ); } void CInEdit::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) { CRect rtClient; lpwndpos->x = m_left; // m_left在LVN_BEGINLABELEDIT中设置 CEdit::OnWindowPosChanging(lpwndpos); // TODO: Add your message handler code here } 源文档 <http://www.cppblog.com/justin-shi/archive/2008/06/14/53192.html> m_pCtrl = &this->GetListCtrl(); //获得指针 //CListCtrl样式改变 LONG lStyle; lStyle = GetWindowLong(m_pCtrl->m_hWnd, GWL_STYLE); //获取当前窗口 style lStyle &= ~LVS_TYPEMASK; //清除显示方式 lStyle |= LVS_REPORT; //设置style 为Report显示 SetWindowLong(m_pCtrl->m_hWnd, GWL_STYLE, lStyle); //CListCtrl扩展样式改变 DWORD dwStyle; dwStyle = m_pCtrl->GetStyle(); //取得样式 dwStyle |= LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT ; //添加样式 m_pCtrl->SetExtendedStyle(dwStyle); //重新设置 //插入列 m_pCtrl->InsertColumn(1,"第一列",LVCFMT_CENTER,47); //序 号,标题,标题显示位置,列宽度 m_pCtrl->InsertColumn(2,"第二列",LVCFMT_CENTER,100); //写入数据 int nRow = m_list.InsertItem(0, “无用字符串”); //插入行 m_list.SetItemText(nRow, 1, “1111”); //设置数据 m_list.SetItemText(nRow, 2, “2222”); //设置数据 int n = -1; POSITION pos = m_pCtrl->GetFirstSelectedItemPosition(); //返回第一个选中的行位置 if (pos != NULL) { while (pos) { n = m_pCtrl->GetNextSelectedItem(pos); //返回下一个选中的行数(返回值从0开始) //做相应操作 } } //直接用VC类向导生成后,不用再次添加声明和消息映射 //添加函数声明 afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult); //添加消息映射 ON_NOTIFY_REFLECT(NM_CLICK, OnClick) void CMyListView::OnClick(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { /* CString strtemp; strtemp.Format("单击的是第%d行第%d列", pNMListView->iItem, pNMListView->iSubItem); AfxMessageBox(strtemp); */ //值从0开始计算,无数据区不相应 时间 //相应操作 } *pResult = 0; } LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 这四种风格决定控件的外观,同时只可以选择其中一种,分别对应:大图标显示,小图标显示,列表显示,详细报表显示 LVS_EDITLABELS 结点的显示字符可以被编辑,对于报表风格来讲可编辑的只为第一列。 LVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点 LVS_SINGLESEL 同时只能选中列表中一项 LVN_BEGINLABELEDIT 在开始某项编辑字符时发送,所用结构:NMLVDISPINFO LVN_ENDLABELEDIT 在结束某项编辑字符时发送,所用结构:NMLVDISPINFO LVN_GETDISPINFO 在需要得到某项信息时发送,(如得到某项的显示字符)所用结构:NMLVDISPINFO 列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性 值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些列表控件的专用风格: 首先你需要设置列表控件所使用的ImageList,如果你使用大图标显示风格,你就需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL); 如果使用其它三种风格显示而不想显示图标你可以不进行任何设置,否则需要以如下形式调用: CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL); 通过调用int InsertItem( int nItem, LPCTSTR lpszItem );可以在列表控件中nItem指明位置插入一项,lpszItem为显示字符。除LVS_REPORT风格外其他三种风格都只需要直接调用 InsertItem就可以了,但如果使用报表风格就必须先设置列表控件中的列信息。 通过调用int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);可以插入列。iCol为列的位置,从零开始,lpszColumnHeading为显示的列名,nFormat为显示对齐方式, nWidth为显示宽度,nSubItem为分配给该列的列索引。 在有多列的列表控件中就需要为每一项指明其在每一列中的显示字符,通过调用 BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );可以设置每列的显示字符。nItem为设置的项的位置,nSubItem为列位置,lpszText为显示字符。下面的代码演示了如何设置多列并插入 数据: m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//设置ImageList m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//设置列 m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1); m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2); m_list.InsertItem(0,"Item 1_1");//插入行 m_list.SetItemText(0,1,"Item 1_2");//设置该行的不同列的显示字符 m_list.SetItemText(0,2,"Item 1_3"); 此外CListCtrl还提供了一些函数用于得到/修改控件的状态。 COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr );用于得到/设置显示的字符颜色。 COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr );用于得到/设置显示的背景颜色。 void SetItemCount( int iCount );用于得到添加进列表中项的数量。 BOOL DeleteItem(int nItem);用于删除某一项,BOOL DeleteAllItems( );将删除所有项。 BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent);用于设置背景位图。 CString GetItemText( int nItem, int nSubItem );用于得到某项的显示字符。 列表控件的消息映射同样使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于列表控件可能取值和对应的数据结构为: 关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。 关于动态提供结点所显示的字符:首先你在项时需要指明 lpszItem参数为: LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数 pNMHDR转换为LPNMLVDISPINFO,然后填充其中item.pszText。通过item中的iItem,iSubItem可以知道当前显 示的为那一项。下面的代码演示了这种方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加结点 m_list.InsertItem(LPSTR_TEXTCALLBACK,...) m_list.InsertItem(LPSTR_TEXTCALLBACK,...) //处理消息 void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; pLVDI->item.pszText=szOut[pTVDI->item.iItem];//通过iItem得到需要显示的字符在数组中的位置 *pResult = 0; } 关于编辑某项的显示字符:(在报表风格中只对第一列有效)首先需 要设置列表控件的 LVS_EDITLABELS风格,在开始编辑时该控件将会发送LVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来 的编辑,在编辑完成后会发送LVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMLVDISPINFO,然后通过其中 的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.iItem==0);//判断是否取消该操作 *pResult = 1; else *pResult = 0; } //处理消息 LVN_BEGINLABELEDIT void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR; if(pLVDI->item.pszText==NULL);//判断是否已经取消取消编辑 m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText);//重置显示字符 *pResult = 0; } 上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处 理)。 如何得到当前选中项位置:在列表控件中没有一个类似于 ListBox中GetCurSel()的函数,但是可以通过调用GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);得到选中项位置。 下面是一些例子 作者:lixiaosan 时间:04/06/2006 以下未经说明,listctrl默认view 风格为report 相关类及处理函数 MFC:CListCtrl类 SDK:以 “ListView_”开头的一些宏。如 ListView_InsertColumn 1. CListCtrl 风格 LVS_ICON: 为每个item显示大图标 LVS_SMALLICON: 为每个item显示小图标 LVS_LIST: 显示一列带有小图标的item LVS_REPORT: 显示item详细资料 直观的理解:windows资源管理器,“查看”标签下的“大图标,小图标,列表,详细资料” 2. 设置listctrl 风格及扩展风格 LONG lStyle; lStyle. = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style lStyle. &= ~LVS_TYPEMASK; //清除显示方式位 lStyle.|= LVS_REPORT; //设置style SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style DWORD dwStyle. = m_list.GetExtendedStyle(); dwStyle.|= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl) dwStyle.|= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl) dwStyle.|= LVS_EX_CHECKBOXES;//item前生成checkbox控件 m_list.SetExtendedStyle(dwStyle); //设置扩展风格 注:listview的style请查阅msdn http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp 3. 插入数据 m_list.InsertColumn( 0, "ID", LVCFMT_LEFT, 40 );//插入列 m_list.InsertColumn( 1, "NAME", LVCFMT_LEFT, 50 ); int nRow = m_list.InsertItem(0, “11”);//插入行 m_list.SetItemText(nRow, 1, “jacky”);//设置数据 4. 一直选中item 选中style中的Show selection always,或者在上面第2点中设置LVS_SHOWSELALWAYS 5. 选中和取消选中一行 int nIndex = 0; //选中 m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); //取消选中 m_list.SetItemState(nIndex, 0, LVIS_SELECTED|LVIS_FOCUSED); 6. 得到listctrl中所有行的checkbox的状态 m_list.SetExtendedStyle(LVS_EX_CHECKBOXES); CString str; for(int i=0; i<m_list.GetItemCount(); i++) { if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED || m_list.GetCheck(i)) { str.Format(_T("第%d行的checkbox为选中状态"), i); AfxMessageBox(str); } } 7. 得到listctrl中所有选中行的序号 方法一: CString str; for(int i=0; i<m_list.GetItemCount(); i++) { if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED ) { str.Format(_T("选中了第%d行"), i); AfxMessageBox(str); } } 方法二: POSITION pos = m_list.GetFirstSelectedItemPosition(); if (pos == NULL) TRACE0("No items were selected!/n"); else { while (pos) { int nItem = m_list.GetNextSelectedItem(pos); TRACE1("Item %d was selected!/n", nItem); // you could do your own processing on nItem here } } 8. 得到item的信息 TCHAR szBuf[1024]; LVITEM lvi; lvi.iItem = nItemIndex; lvi.iSubItem = 0; lvi.mask = LVIF_TEXT; lvi.pszText = szBuf; lvi.cchTextMax = 1024; m_list.GetItem(&lvi); 关于得到设置item的状态,还可以参考msdn文章 Q173242: Use Masks to Set/Get Item States in CListCtrl http://support.microsoft.com/kb/173242/en-us 9. 得到listctrl的所有列的header字符串内容 LVCOLUMN lvcol; char str[256]; int nColNum; CString strColumnName[4];//假如有4列 nColNum = 0; lvcol.mask = LVCF_TEXT; lvcol.pszText = str; lvcol.cchTextMax = 256; while(m_list.GetColumn(nColNum, &lvcol)) { strColumnName[nColNum] = lvcol.pszText; nColNum++; } 10. 使listctrl中一项可见,即滚动滚动条 m_list.EnsureVisible(i, FALSE); 11. 得到listctrl列数 int nHeadNum = m_list.GetHeaderCtrl()->GetItemCount(); 12. 删除所有列 方法一: while ( m_list.DeleteColumn (0)) 因为你删除了第一列后,后面的列会依次向上移动。 方法二: int nColumns = 4; for (int i=nColumns-1; i>=0; i--) m_list.DeleteColumn (i); 13. 得到单击的listctrl的行列号 添加listctrl控件的NM_CLICK消息相应函数 void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) { // 方法一: /* DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_list.ScreenToClient(&point); LVHITTESTINFO lvinfo; lvinfo.pt = point; lvinfo.flags = LVHT_ABOVE; int nItem = m_list.SubItemHitTest(&lvinfo); if(nItem != -1) { CString strtemp; strtemp.Format("单击的是第%d行第%d列", lvinfo.iItem, lvinfo.iSubItem); AfxMessageBox(strtemp); } */ // 方法二: /* NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { CString strtemp; strtemp.Format("单击的是第%d行第%d列", pNMListView->iItem, pNMListView->iSubItem); AfxMessageBox(strtemp); } */ *pResult = 0; } 14. 判断是否点击在listctrl的checkbox上 添加listctrl控件的NM_CLICK消息相应函数 void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) { DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_list.ScreenToClient(&point); LVHITTESTINFO lvinfo; lvinfo.pt = point; lvinfo.flags = LVHT_ABOVE; UINT nFlag; int nItem = m_list.HitTest(point, &nFlag); //判断是否点在checkbox上 if(nFlag == LVHT_ONITEMSTATEICON) { AfxMessageBox("点在listctrl的checkbox上"); } *pResult = 0; } 15. 右键点击listctrl的item弹出菜单 添加listctrl控件的NM_RCLICK消息相应函数 void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->iItem != -1) { DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); CMenu menu; VERIFY( menu.LoadMenu( IDR_MENU1 ) ); CMenu* popup = menu.GetSubMenu(0); ASSERT( popup != NULL ); popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ); } *pResult = 0; } 16. item切换焦点时(包括用键盘和鼠标切换item时),状态的一些变化顺序 添加listctrl控件的LVN_ITEMCHANGED消息相应函数 void CTest6Dlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here CString sTemp; if((pNMListView->uOldState & LVIS_FOCUSED) == LVIS_FOCUSED && (pNMListView->uNewState & LVIS_FOCUSED) == 0) { sTemp.Format("%d losted focus",pNMListView->iItem); } else if((pNMListView->uOldState & LVIS_FOCUSED) == 0 && (pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED) { sTemp.Format("%d got focus",pNMListView->iItem); } if((pNMListView->uOldState & LVIS_SELECTED) == LVIS_SELECTED && (pNMListView->uNewState & LVIS_SELECTED) == 0) { sTemp.Format("%d losted selected",pNMListView->iItem); } else if((pNMListView->uOldState & LVIS_SELECTED) == 0 && (pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED) { sTemp.Format("%d got selected",pNMListView->iItem); } *pResult = 0; } 17. 得到另一个进程里的listctrl控件的item内容 http://www.codeproject.com/threads/int64_memsteal.asp 18. 选中listview中的item Q131284: How To Select a Listview Item Programmatically http://support.microsoft.com/kb/131284/en-us 19. 如何在CListView中使用CListCtrl的派生类 http://www.codeguru.com/cpp/controls/listview/introduction/article.php/c919/ 20. listctrl的subitem添加图标 m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES); m_list.SetItem(..); //具体参数请参考msdn 21. 在CListCtrl显示文件,并根据文件类型来显示图标 网上找到的代码,share BOOL CTest6Dlg::OnInitDialog() { CDialog::OnInitDialog(); HIMAGELIST himlSmall; HIMAGELIST himlLarge; SHFILEINFO sfi; char cSysDir[MAX_PATH]; CString strBuf; memset(cSysDir, 0, MAX_PATH); GetWindowsDirectory(cSysDir, MAX_PATH); strBuf = cSysDir; sprintf(cSysDir, "%s", strBuf.Left(strBuf.Find("//")+1)); himlSmall = (HIMAGELIST)SHGetFileInfo ((LPCSTR)cSysDir, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON ); himlLarge = (HIMAGELIST)SHGetFileInfo((LPCSTR)cSysDir, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_LARGEICON); if (himlSmall && himlLarge) { ::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL, (LPARAM)himlSmall); ::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL, (LPARAM)himlLarge); } return TRUE; // return TRUE unless you set the focus to a control } void CTest6Dlg::AddFiles(LPCTSTR lpszFileName, BOOL bAddToDocument) { int nIcon = GetIconIndex(lpszFileName, FALSE, FALSE); CString strSize; CFileFind filefind; // get file size if (filefind.FindFile(lpszFileName)) { filefind.FindNextFile(); strSize.Format("%d", filefind.GetLength()); } else strSize = "0"; // split path and filename CString strFileName = lpszFileName; CString strPath; int nPos = strFileName.ReverseFind('//'); if (nPos != -1) { strPath = strFileName.Left(nPos); strFileName = strFileName.Mid(nPos + 1); } // insert to list int nItem = m_list.GetItemCount(); m_list.InsertItem(nItem, strFileName, nIcon); m_list.SetItemText(nItem, 1, strSize); m_list.SetItemText(nItem, 2, strFileName.Right(3)); m_list.SetItemText(nItem, 3, strPath); } int CTest6Dlg::GetIconIndex(LPCTSTR lpszPath, BOOL bIsDir, BOOL bSelected) { SHFILEINFO sfi; memset(&sfi, 0, sizeof(sfi)); if (bIsDir) { SHGetFileInfo(lpszPath, FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(sfi), SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES |(bSelected ? SHGFI_OPENICON : 0)); return sfi.iIcon; } else { SHGetFileInfo (lpszPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES | (bSelected ? SHGFI_OPENICON : 0)); return sfi.iIcon; } return -1; } 22.MFC的CListCtrl的排序功能 // 排序用的比较函数 staticintCALLBACK MyCompareProc(LPARAMlParam1, LPARAMlParam2, LPARAMlParamSort) { CString &lp1 = *((CString *)lParam1); CString &lp2 = *((CString *)lParam2); int &sort = *(int *)lParamSort; if (sort == 0) { returnlp1.CompareNoCase(lp2); } else { returnlp2.CompareNoCase(lp1); } } //要处理的事件 ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, &CDlg::OnLvnColumnclickList1) //处理代码 voidCDlg::OnLvnColumnclickList1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLISTVIEWpNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); intLength = m_ListCtrl.GetItemCount(); CArray<CString,CString> ItemData; ItemData.SetSize(Length); for (inti = 0; i < Length; i++) { ItemData[i] = m_ListCtrl.GetItemText(i,pNMLV->iSubItem); m_ListCtrl.SetItemData(i,(DWORD_PTR)&ItemData[i]);//设置排序关键字 } staticintsort = 0; staticintSubItem = 0; if (SubItem != pNMLV->iSubItem) { sort = 0; SubItem = pNMLV->iSubItem; } else { if (sort == 0) { sort = 1; } else { sort = 0; } } m_ListCtrl.SortItems(MyCompareProc,(DWORD_PTR)&sort);//排序 *pResult = 0; } 23.CListCtrl显示样式的改变 需要的样式(根据自己的需要的样式选择) LVS_ICON: 为每个item显示大图标 LVS_SMALLICON: 为每个item显示小图标 LVS_LIST: 显示一列带有小图标的item LVS_REPORT: 显示item详细资料 LVS_EX_FULLROWSELECT: 表示选中某行使整行高亮(只适用与report风格的CListCtrl) LVS_EX_GRIDLINES: 表示显示网格线(只适用与report风格的CListCtrl) 24.添加CListCtrl的记录 25.判断CListCtrl的哪行记录被选中了 26.响应单击CListCtrl事件 //响应CMyListView的=NUM_CLICK消息 27 CListCtrl,CListView与LVN_ITEMCHANGED消息 若要在CListCtrl中行发生改变时得到通知,可以映射 LVN_ITEMCHANGED消息。 ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemchanged) afx_msg void OnItemchanged(NMHDR* pNMHDR,LRESULT* pResult); // 行选择改变 void CMyListCtrl::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; ...您要进行的操作... *pResult = 0; } 注意,LVN_ITEMCHANGED消息的产生有以下几种可能: 1、由选中到没选中的变化; 2、由没选中到选中的变化; 3、由选中一行到选中另外一行的变化; 4、使用CListCtrl::SetItem函数更改了行; 如何检测LVN_ITEMCHANGED消息是由那一变化产生的呢? NM_LISTVIEW结构成员变量uChanged和uNewState包含着这类信息,看如下代码: void CRunListView::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if(pNMListView->uChanged == LVIF_STATE) { if(pNMListView->uNewState) TRACE0("选择改变且有选中的行/r/n"); else TRACE0("选择改变且没有选中的行/r/n"); } else TRACE0("行改变(CListCtrl::SetItem)/r/n"); *pResult = 0; }
以上内容都是转载的网上整理的比较全面的文章,个人将以上文章中没有提到关于列表控件的其他方面的一些用法做以下说明:
1.关于DeleteItem的疑问
好多人在网上问为什么列表框的控件选项的顺序有的时候让我们摸不着头脑,举个例子吧,请看下面的两段代码
int nCount = m_myListCtrl.GetItemCount(); // Delete all of the items from the list view control. for (int i=0; i < nCount; i++) { m_myListCtrl.DeleteItem(0); }
int nCount = m_myListCtrl.GetItemCount(); // Delete all of the items from the list view control. for (int i=0; i < nCount; i++) { m_myListCtrl.DeleteItem(i); }
这两段代码有什么不一样的地方吗?它们执行的功能一样吗?
大家试试就知道了,完全不一样
第一段是删除所有的列表项
第二段是只删除了序号为偶数的列表项
为什么?why?这个问题折磨了 我一上午,原来列表控件对列表选项有自动排列的功能,删除一项,其余的序号和GetItemCount()的值也都会发生改变,那如何删除当初已经确定好序号的列表项呢?以下是我自己写的一段算法代码,仅供参考,若你有更好的方法请不吝赐教!
int i=0; do { if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED && m_list.GetCheck(i)) { m_list.DeleteItem(i); i=0; } else if(!m_list.GetCheck(i)) i++; }while(i<m_list.GetItemCount());