来源网站:http://www.yesky.com/72/27572.shtml
列表控件(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也可以设置该值。由于你在排序时只能通过该值来确定项的位置所以你应该比较明确的确定该值的含义。
下面我们看一个例子,这个例子是一个派生类,并支持顺序/倒序两种方式排序。
//全局数据 struct DEMO_DATA { char szName[20]; int iAge; }strAllData[5]={{"王某",30},{"张某",40},{"武某",32},{"陈某",20},{"李某",36}}; //使用方法 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 } //类定义 class CSortList : public CListCtrl { // Construction public: CSortList(); BOOL m_fAsc;//是否? 排序 int m_nSortedCol;//当前排序的列 protected: //{{AFX_MSG(CSortList) //}}AFX_MSG //手工定义消息映射,处理顶部按钮被按下的消息 afx_msg void OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult); ... }; //CPP文件 //排序函数 int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); CSortList::CSortList() { m_fAsc=TRUE; } CSortList::~CSortList() { } BEGIN_MESSAGE_MAP(CSortList, CListCtrl) //{{AFX_MSG_MAP(CSortList) //}}AFX_MSG_MAP //手工定义消息映射,处理顶部按钮被按下的消息 ON_NOTIFY(HDN_ITEMCLICK, 0, OnHeaderClicked) END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CSortList message handlers //处理顶部按钮被按下的消息 void CSortList::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult) { HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR; if( phdn->iButton == 0 ) { //设置排序方式 if( phdn->iItem == m_nSortedCol ) m_fAsc = !m_fAsc; else m_fAsc = TRUE; //设置排序的列 m_nSortedCol = phdn->iItem; //开始排序 SortItems( ListCompare, (DWORD)this ); } }
//排序函数实现 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; }