欢迎访问:常州市武进区嘉泽中心小学网站 !今天是:
栏目列表
您现在的位置是:首页>>教师>>计算机技术>>程序设计>>杂项>>文章内容
自身支持排序的ListCtrl
发布时间:2008-11-20   点击:   来源:本站原创   录入者:佚名
 

自身支持排序的ListCtrl


VC里的CListCtrl是个很不好用的控件,特别是排序,实现起来很麻烦。

关于排序的基本用法,有一篇很好的文章:
=

但是,在这个例子里也存在个问题:排序的实现是和数据源相关的,如果有若干个表需要排序的话,每个表都要写相应的代码,这是一件非常痛苦的事。

所以,在上面的基础上,重新写了一个自身支持排序的CSoftList,从某个意义上说,也算是实现文档和视图的真正分离。

下面说说几个主要的地方。


1. CSortList是CListCtrl的派生类 (好象是废话)

2. 要让CSortList自行排序,当然得让CSortList自己处理LVN_COLUMNCLICK消息
 ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnLvnColumnclick)
   OnLvnColumnclick的作用就是设置排序列,排序方式,最后调用SortItems()。

3. 排序的具体实现,也就是CALLBACK ListCompare(...)的实现:
   基本要求: 让CSortList根据Item进行排序,而与数据源无关。(当然这样也有不足之处,就是排序只能按文本排序了。如果你需要按数字排序的话,那就只有特殊处理了。)

   这里涉及到的最主要的函数是:
   1)ListCompare - 实现排序的回调函数
   int CALLBACK CSortList::ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
   2)CListCtrl::FindItem - 查找相应的Item, 查找方式可指定
   int FindItem( LVFINDINFO* pFindInfo, int nStart = -1 ) const;
   FindItem的具体细节请参考MSDN.
  
   基本思路:
   1)ListCompare的原型:传入的参数lParam1,lParam2是相应两行的ItemData;
   2)FindItem根据lParam1,lParam2得到相应的Item;
     FindItem有多种查找方式(查找方式通过LVFINDINFO->flags进行设置),这里只是根据ItemData进行查找。
   3)再用GetItemText得到排序列的ItemText;
   4)最后就是比较ItemText了。
  
4. 显示指明排序方式的标记
   简单地说,就是给CListCtrl的CHeadCtrl指定一个CImageList,根据需要指定Column要显示的Image。
   主要函数:
   1)CHeaderCtrl::GetItem - 取得表头控制中某一项目的内容
   BOOL GetItem( int nPos, HDITEM* pHeaderItem ) const;
   2)CHeaderCtrl::SetItem - 设置表头控制中某一项目的内容
   BOOL SetItem( int nPos, HDITEM* pHeaderItem );


下面是源代码:
只有两个文件:CSortList.H, CSortList.cpp
直接把这两个文件放到项目里就可以了。
唯一要注意的是:IDB_HDRUP, IDB_HDRDOWN 是两个位图资源,分别表示顺序和倒序,这个就需要自己弄了。

A. SoftList.h

#if !defined(AFX_SORTLIST_H__6ACE2F6F_AEFE_11D3_BDE9_F4145AA4F676__INCLUDED_)
#define AFX_SORTLIST_H__6ACE2F6F_AEFE_11D3_BDE9_F4145AA4F676__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// SortList.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CSortList window

class CSortList : public CListCtrl
{
// Construction
public:
 CSortList();
// Attributes
public:

// Operations
public:

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CSortList)
 //}}AFX_VIRTUAL

// Implementation
public:
 virtual ~CSortList();

 // Generated message map functions
protected:
 //{{AFX_MSG(CSortList)
 afx_msg bool OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult);
 //}}AFX_MSG
  
 DECLARE_MESSAGE_MAP()
public:
 afx_msg void OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult);

 void CreateSortIcons();
 void SetSortIcon();

 bool GetFullRowSelect();
 // 设置为行选中
 void SetFullRowSelect( bool bFullRowSelect );

 bool GetGridLines();
 // 设置绘制表格
 void SetGridLines( bool bGridLines );

 static CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
public:
 BOOL m_bAsc;//是否顺序排序
 int m_nSortedCol;//当前排序的列

private:
 CBitmap                            m_bmpUpArrow; 
 CBitmap                            m_bmpDownArrow;
 int                                m_nUpArrow;
 int                                m_nDownArrow;
 CImageList                         m_imglstSortIcons;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_SORTLIST_H__6ACE2F6F_AEFE_11D3_BDE9_F4145AA4F676__INCLUDED_)

B. SoftList.cpp

// SortList.cpp : implementation file
//

#include "stdafx.h"
#include "SortList.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSortList

CSortList::CSortList()
{
 m_bAsc=TRUE;
 //this->m_nSortedCol = -1;
 CreateSortIcons();
 //GetHeaderCtrl()->SetImageList(&m_imglstSortIcons);
}

CSortList::~CSortList()
{
 m_imglstSortIcons.DeleteImageList();
    m_bmpUpArrow.DeleteObject();
    m_bmpDownArrow.DeleteObject();
}

BEGIN_MESSAGE_MAP(CSortList, CListCtrl)
 //{{AFX_MSG_MAP(CSortList)
 //}}AFX_MSG_MAP
 ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnLvnColumnclick)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSortList message handlers

void CSortList::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
 LPNMLISTVIEW pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
 // TODO: Add your control notification handler code here
 //NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
 if( pNMListView->iSubItem == m_nSortedCol )
  m_bAsc = !m_bAsc;
 else
 {
  m_bAsc = TRUE;
  m_nSortedCol = pNMListView->iSubItem;
 }
 SortItems( ListCompare, (DWORD)this );
 SetSortIcon();
 *pResult = 0;
}


void CSortList::CreateSortIcons()
{
  if (!m_imglstSortIcons.m_hImageList)
  {
 COLORMAP cm = {RGB(0, 0, 0), GetSysColor(COLOR_GRAYTEXT)};
    m_imglstSortIcons.Create   (9, 5, ILC_COLOR24 | ILC_MASK, 2, 0);
    m_bmpUpArrow.LoadMappedBitmap(IDB_HDRUP, 0, &cm, 1);
    m_nUpArrow = m_imglstSortIcons.Add(&m_bmpUpArrow, RGB(255, 255, 255));
    m_bmpDownArrow.LoadMappedBitmap(IDB_HDRDOWN, 0, &cm, 1);
    m_nDownArrow = m_imglstSortIcons.Add(&m_bmpDownArrow, RGB(255, 255, 255));
  }
}

void CSortList::SetSortIcon()
{
 CHeaderCtrl* pHeaderCtrl = this->GetHeaderCtrl();
 ASSERT(pHeaderCtrl);

 pHeaderCtrl->SetImageList(&m_imglstSortIcons);
 for( int col = 0; col< GetHeaderCtrl()->GetItemCount(); col++ )
 {
  HDITEM hdrItem = { 0,};
   
        hdrItem.mask = HDI_FORMAT | HDI_IMAGE;

  BOOL ret = pHeaderCtrl->GetItem(col-1, &hdrItem);
  ret = pHeaderCtrl->GetItem(col+1, &hdrItem);
        ret = pHeaderCtrl->GetItem(col, &hdrItem);
        if ( m_nSortedCol == col)
        {
   hdrItem.fmt = hdrItem.fmt & HDF_JUSTIFYMASK | HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
   if( m_bAsc )
    hdrItem.iImage = m_nUpArrow;
   else
    hdrItem.iImage = m_nDownArrow;
        }
        else
  {
   hdrItem.fmt = hdrItem.fmt & HDF_JUSTIFYMASK | HDF_STRING;
  }
  pHeaderCtrl->SetItem(col, &hdrItem);
 }
}

bool CSortList::GetFullRowSelect()
{
 return ( GetExtendedStyle()&LVS_EX_FULLROWSELECT) == LVS_EX_FULLROWSELECT;
}

void CSortList::SetFullRowSelect( bool bFullRowSelect )
{
 if( bFullRowSelect )
  SetExtendedStyle( GetExtendedStyle()|LVS_EX_FULLROWSELECT );
 else
  SetExtendedStyle( GetExtendedStyle()&(~LVS_EX_FULLROWSELECT) ); 
}

bool CSortList::GetGridLines()
{
 return ( GetExtendedStyle() & LVS_EX_GRIDLINES ) == LVS_EX_GRIDLINES;
}

void CSortList::SetGridLines( bool bGridLines )
{
 if( bGridLines )
  SetExtendedStyle( GetExtendedStyle()|LVS_EX_GRIDLINES );
 else
  SetExtendedStyle( GetExtendedStyle()&(~LVS_EX_GRIDLINES) ); 
}

int CALLBACK CSortList::ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
 CSortList* pList=(CSortList*)lParamSort;
 int nItem1, nItem2;
    
    LVFINDINFO FindInfo;
    FindInfo.flags = LVFI_PARAM;    // 指定查找方式
    FindInfo.lParam = lParam1;
    nItem1 = pList->FindItem(&FindInfo, -1); // 得到对应Item索引
    FindInfo.lParam = lParam2;
    nItem2 = pList->FindItem(&FindInfo, -1);

 if((nItem1 == -1) || (nItem2 == -1))
    {
     TRACE("无法找到!\n");
  return 0;
    }

 CString Str1,Str2;
 Str1 = pList->GetItemText(nItem1, pList->m_nSortedCol); // 得到排序列的Text
    Str2 = pList->GetItemText(nItem2, pList->m_nSortedCol);
 int iCompRes = 0;
 if(Str1 > Str2)
  iCompRes = 1;
    else if(Str1 == Str2)
  iCompRes = 0;
    else
  iCompRes = -1;

 if(pList->m_bAsc)
  return iCompRes;
 else
  return iCompRes*-1;
 return 0;
}


附件:
    关闭窗口
    打印文档
    账号登录
    保持登录 忘记密码?
    账号与武进教师培训平台同步