|
自身支持排序的ListCtrl VC里的CListCtrl是个很不好用的控件,特别是排序,实现起来很麻烦。
关于排序的基本用法,有一篇很好的文章: http://www.vchelp.net/vchelp/zart/sortl.asp?type_id=9&class_id=1&cata_id=1&article_id=73&search_term= 但是,在这个例子里也存在个问题:排序的实现是和数据源相关的,如果有若干个表需要排序的话,每个表都要写相应的代码,这是一件非常痛苦的事。 所以,在上面的基础上,重新写了一个自身支持排序的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; }
|