Chinaunix首页 | 论坛 | 博客
  • 博客访问: 670926
  • 博文数量: 81
  • 博客积分: 1659
  • 博客等级: 上尉
  • 技术积分: 1286
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-02 16:36
个人简介

专注于嵌入式和图像处理

文章分类

全部博文(81)

文章存档

2014年(1)

2013年(7)

2012年(46)

2011年(27)

分类: C/C++

2012-10-07 11:30:48

下面要做一个CListCtrl控件,当用户点击某列标题的时候,就根据该列数据进行全部记录的升序或降序排列。步骤如下:
1.从CListCtrl类继承,新建一个新的列表控件类,这里我把它命名为CSortListCtrl。
2.为CSortListCtrl类添加以下成员变量:
  BOOL m_fAsc;                  //用来设置是升序排列还是降序排列
  int m_nSortedCol;             //用来记录被点击的是哪一列
3.在CSortListCtrl类的构造函数中添加m_fAsc=TRUE;把排序初始化为按升序排序。
4.当列标题被点击的时候,会促发LVN_COLUMNCLICK消息,因此对CSortListCtrl类的LVN_COLUMNCLICK消息进行消息响应,进行排序操作。
消息响应函数如下:
void CSortListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
{
 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 for (int index=0;index  SetItemData(index,index); 
//SetItemData函数的作用是为一行设置一个标签,以后通过该标签就能找回这一行,标签是一个数值。SetItemData(index,index)意思就是这一行是第几列就把标签设为几。为什么要设置标签呢?以后的排序必须用到标签。
 if( pNMListView->iSubItem == m_nSortedCol )     //如果被点击的列和上一次点击的列是同一列的话
  m_fAsc = !m_fAsc;                             //排序方式取反,即上次是升序这次就为降序,上次降序这次就为升序
 else                                                   //如果被点击的列和上一次点击的列不是同一列的话
 {
  m_fAsc = TRUE;                               //排序方式为升序
  m_nSortedCol = pNMListView->iSubItem;        //把这次点击的列序号保存到m_nSortedCol 变量中
 }
 SortItems( ListCompare, (DWORD)this );    
//SortItems函数进行排序操作,ListCompare是回调函数,SortItems函数会调用此回调函数进行排序判断

 *pResult = 0;
}
以下为回调函数的实现,回调函数必须为全局函数。
int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
 CSortListCtrl* pV=(CSortListCtrl*)lParamSort;
 
CString Comp1NAME,Comp2NAME,Comp1SUM,Comp2SUM;
int SUM1,SUM2;
int iCompRes;
 switch(pV->m_nSortedCol)   //判断被点击的是哪一列
 {
 case(0):                                //如果被点击的是第一列(假设第一列是字符型数据)
  {
  for(int i=0;iGetItemCount();i++)
  { 
   if (  lParam1==pV->GetItemData(i))         //寻找标签为参数lParam1的哪一行
     Comp1NAME=pV->GetItemText(i,0);     //把这行第一列的内容提取出来
    
   if ( lParam2==pV->GetItemData(i))         //寻找标签为参数lParam2的哪一行
     Comp2NAME=pV->GetItemText(i,0);     //把这行第一列的内容提取出来
  }
  iCompRes=Comp1NAME.Compare(Comp2NAME);    //把内容进行比较,结果保存到iCompRes上
  break;
  }
  case(1):                                                  //如果被点击的是第二列(假设第二列是整型数据)
  {
  for(int i=0;iGetItemCount();i++)
  { 
   if (  lParam1==pV->GetItemData(i))
   {Comp1SUM=pV->GetItemText(i,1);
    SUM1=atoi(Comp1SUM);
   } 
   if ( lParam2==pV->GetItemData(i))
   {Comp2SUM=pV->GetItemText(i,1);
    SUM2=atoi(Comp2SUM);
   }
  }
  if(SUM1 == SUM2) 
   iCompRes = 0;
//标签为lParam1行第一列的数据SUM1等于标签为lParam2行第一列的数据SUM2则返回0
  else
   iCompRes=(SUM1 < SUM2)?-1:1;            
//标签为lParam1行第一列的数据SUM1小于标签为lParam2行第一列的数据SUM2则返回-1,大于则返回1
  break;
  }
  default:  
  break;
 }
 //根据当前的排序方式进行调整,返回应当如何排序。函数返回-1代表第一项排应在第二项前面,返回1代表第一项排应在第二项后面,返回0代表两项相等。
 if(pV->m_fAsc)        //升序排列
  return iCompRes;  //switch里面的比较就是按照升序排列来返回结果
 else                         //降序排列
  return iCompRes*-1;
}
注意,在以上的例子中我只假设了列表控件只有两列而且点击这两列都能进行排序,如果你的列表有多列,而点击某些列你又不想激活排序的话,就必须在void CSortListCtrl::OnColumnclick函数开头进行判断,判断出如果点击的列是不想激活排序的列的话就马上让函数return掉,不执行往后的排序操作。另外需要激活排序的列必须都能在回调函数里的switch判断中找到该列的入口,否则的话就会从default跳出,没做任何比较就返回函数结果,排序就会不正确。
阅读(1434) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~