在ListCtrl中进行排序问题
2005-08-19 10:47
501 查看
列表控件(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消息进行处理来实现。
下面我们看一个例子,这个例子是一个派生类,并支持顺序/倒序两种方式排序。为了简单我对全局数据进行排序,而在实际应用中会有多组需要排序的数据,所以需要通过传递参数的方式来告诉派序函数需要对什么数据进行排序。
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; }
关于"在ListCtrl中进行排序问题"的补充 如果没有定义DEMO_DATA,如何直接用GetItemText得到文本进行排序。 这里的关键问题是在 1. 在InsertItem及SetItemText后,用BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )来对每一项的ItemData进行设置。目的是:设置每项的ItemData为数据的索引,在排序函数中通过该ItemData来确定数据 2. 排序函数的参数LPARAM lParam1, LPARAM lParam2是进行比较的两项的ItemData。用int FindItem( LVFINDINFO* pFindInfo, int nStart = -1 ) const;得到ItemData对应Item。 3. 根据此Item,由Cstring GetItemText( int nItem, int nSubItem ) const;得到对应Cstring4. 用strcmp进行比较. 下面是排序函数的实现: int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { CSortList* pV=(CSortList*)lParamSort; CString strItem1, strItem2; LVFINDINFO info; int nIndex; info.flags = LVFI_PARAM; //设置为LVFI_PARAM,后面的FindItem才能有效,详情参考MSDN的LVFINDINFO info.lParam = lParam1; //由item data(lParam1)得到对应的item text if ( (nIndex=pV->FindItem(&info)) != -1) strItem1 = pV->GetItemText(nIndex, pV->m_nSortedCol); info.lParam = lParam2; //由item data(lParam2)得到对应的item text if ( (nIndex=pV->FindItem(&info)) != -1) strItem2 = pV->GetItemText(nIndex, pV->m_nSortedCol); int iCompRes = strcmp(strItem1, strItem2); //根据当前的排序方式进行调整 if(pV->m_fAsc) return iCompRes; else return iCompRes*-1; }
相关文章推荐
- 在ListCtrl中进行排序(2)
- 巧妙解决mysql删除或添加记录时,对自增主键ID进行重新排序的问题
- 第一周第四天([大小写变换问题][判断是否为email][求对角线的值] [生成数组][数字中添加逗号][生成10个两位随机数,然后再进行排序] [复制数组||将指定数组的指定范围复制到新的数组])
- 关于利用STL中的sort算法对向量等容器进行排序的问题
- PHP中使用asort进行中文排序失效的问题处理
- Linux通过Sort进行多列排序的问题
- 在ListCtrl中进行排序(1)
- 用Array.Sort对字符串进行排序的问题
- js:数组重排序问题:如何使用sort()方法按数值的大小进行升序或降序排列
- 对多个字符串进行排序问题!
- 解决Mysql数据库实现多表联合查询及按照其中一个字段进行排序问题
- 在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题
- Android使用Comparator进行排序报错问题
- 读写文件、文件方法、python2的乱码问题、python对passwd文件进行排序
- 输入任意几个整数,将其进行排序问题。
- [ mathematica 进阶问题 ] 怎么样对含有变量的数组进行排序?
- 一个返回json对象的问题 key 为数字时 会默认从小到大进行排序
- array_multisort 对关联数组进行排序的问题 PHP
- 在ListCtrl中进行排序(二)
- 工作问题小结——通过数组的某个属性进行排序