CMFCListCtrl排序怎么不正常啊?

yanfeiouc2009 2010-08-18 02:44:13
项目中使用CMFCListCtrl控件显示数据库中内容,想按控件中的列进行排序。
从CMFCListCtrl继承了一个类CMyListCtrl。
CMyListCtrl中重载了OnCompareItems(LPARAM lParam1, LPARAM lParam2, int iColumn)函数,在其中添加了两项比较算法,并根据比较结果修改了返回值,算法应该没有问题。

问题是:
1、单击控件某固定列进行排序时,对于初始数据为有序数据的情况排序是正确的,但对于初始无序的列:第一次排序正确,多单击几次就排乱了。
2、排序时先排A列:正确,再排B列回过来再排A列时就排乱了。

大家有没有遇到过这种情况啊,看到坛子里有类似的帖子,但没有明确的答复。恳请各位赐教啊!
...全文
525 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2013-01-11
  • 打赏
  • 举报
回复
yangzongtao 2011-04-28
  • 打赏
  • 举报
回复
好样的三个丑皮匠顶个诸葛亮
yanfeiouc2009 2010-08-18
  • 打赏
  • 举报
回复
补充一下,刚刚看到坛子里“zhupf”的回复中提到的使用CMFCListCtrl实现的排序方法,试了一下,可以实现有效排序。
暂且复制过来,做个总结贴:

//添加一项的时候要使用SetItemData(i,i)绑定一个序号,该序号要唯一
L.SetItemData(i,i); // 一般就设置一个唯一的值.不唯一排序可能有点乱,



//重载的排序比较函数:用于比较两个项的大小关系
int CMFCListCtrlEx::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int iColumn)
{
// pList 是列表控件指针
CString strItem1,strItem2;
LVFINDINFO lvfi;
lvfi.flags=LVFI_PARAM;
lvfi.lParam=lParam1;
strItem1=pList->GetItemText(pList->FindItem(&lvfi,-1),iColumn);
lvfi.lParam=lParam2;
strItem2=pList->GetItemText(pList->FindItem(&lvfi,-1),iColumn);

// 排序 纯粹字符串比较
return _tcsicmp(strItem1, strItem2);
}
yanfeiouc2009 2010-08-18
  • 打赏
  • 举报
回复
好,谢谢了!
iamshuke 2010-08-18
  • 打赏
  • 举报
回复
CListCtrl自带的,给你一份代码吧,自动生成列头上的箭头图标。


#ifndef _SORTLISTCTRL_INCLUDE__
#define _SORTLISTCTRL_INCLUDE__

/////////////////////////////////////////////////////////////////////////////////////////
//一个点击列头时可以排序的列表类
class CSortListCtrl : public CListCtrl
{
// Construction
public:
CSortListCtrl();
// Attributes
public:
struct Info
{
CListCtrl* pListCtrl;
int nSubItem;
BOOL bAsc;
};

int ModiHeardCtrl(CHeaderCtrl* pHeardCtrl,int nItem,int nMode);
static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
// Operations
public:

CImageList m_ImageList;
BOOL m_bInit;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSortListCtrl)
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CSortListCtrl();

// Generated message map functions
protected:
CBitmap* MakeColorBoxImage(BOOL bUp);

//{{AFX_MSG(CSortListCtrl)
afx_msg void OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif

/*
创建人: iamshuke
创建日期: 2002.06.28
说明: 一个单击表头时能排序的列表控件
*/
#include "stdAfx.h"
#include "sortlistctrl.h"

/////////////////////////////////////////////////////////////////////////////
// CSortListCtrl
CSortListCtrl::CSortListCtrl()
{
m_bInit = FALSE;
}

CSortListCtrl::~CSortListCtrl()
{
}

BEGIN_MESSAGE_MAP(CSortListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CSortListCtrl)
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSortListCtrl message handlers
//单击表头时进行排序
void CSortListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;

if(m_bInit == FALSE)
{
m_bInit = TRUE;

m_ImageList.Create(8,8,ILC_COLOR24|ILC_MASK,2,0);
m_ImageList.Add(MakeColorBoxImage(TRUE),RGB(0,0,255));
m_ImageList.Add(MakeColorBoxImage(FALSE),RGB(0,0,255));
GetHeaderCtrl()->SetImageList(&m_ImageList);
}

CHeaderCtrl *pHeardCtrl=GetHeaderCtrl();
for(int i=pHeardCtrl->GetItemCount()-1; i>=0; i--)
{
if(i == pNMListView->iSubItem)
{
continue;
}

ModiHeardCtrl(pHeardCtrl, i, -1);
}

int nMode = ModiHeardCtrl(pHeardCtrl,pNMListView->iSubItem,-2);

Info SortInfo;
SortInfo.pListCtrl = this;
SortInfo.nSubItem = pNMListView->iSubItem;

if(nMode == 0 )
{
SortInfo.bAsc=1;
}
else if(nMode == 1)
{
SortInfo.bAsc=0;
}
else
{
return;
}

int nItemCount = GetItemCount();
DWORD *buf = new DWORD[nItemCount];

for(i=0; i<nItemCount; i++)
{
buf[i] = GetItemData(i);
SetItemData(i,i);
}

//如果只有一列,ListCtrl将不能正确排序,所以添加一临时列,这是ListCtrl的一个BUG。
BOOL bOnlyOneColumn = FALSE;
if(pHeardCtrl->GetItemCount() == 1)
{
InsertColumn(1,"");
bOnlyOneColumn = TRUE;
}

SortItems(MyCompareProc,(DWORD)&SortInfo);

if(bOnlyOneColumn)
{
DeleteColumn(1);//去掉临时列
}

for(i=0; i<nItemCount; i++)
{
SetItemData(i, buf[GetItemData(i)]);
}

delete []buf;
}

int CALLBACK
CSortListCtrl::MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// lParamSort contains a pointer to the list view control.
// The lParam of an item is just its index.

Info *pSortInfo;
pSortInfo=(Info*)lParamSort;

CString strItem1 = pSortInfo->pListCtrl->GetItemText(lParam1, pSortInfo->nSubItem);
CString strItem2 = pSortInfo->pListCtrl->GetItemText(lParam2, pSortInfo->nSubItem);

if(pSortInfo->bAsc)
return strItem1.CompareNoCase(strItem2);
else
return strItem2.CompareNoCase(strItem1);
}


int CSortListCtrl::ModiHeardCtrl(CHeaderCtrl* pHeardCtrl,int nItem,int nMode)
{
HDITEM hdi;
TCHAR lpBuffer[256];
hdi.mask = HDI_TEXT | HDI_IMAGE | HDI_LPARAM | HDI_FORMAT;
hdi.pszText = lpBuffer;
hdi.cchTextMax = 256;

if(pHeardCtrl->GetItem(nItem,&hdi) == FALSE)
{
return -2;
}

if((nMode < -1) || (nMode > 1))
{
nMode= (hdi.lParam == 0 ? 1 : 0) ;
}

hdi.lParam = nMode;

if(nMode == -1)
{
hdi.fmt &= ~HDF_BITMAP_ON_RIGHT;
hdi.fmt &= ~HDF_IMAGE;
hdi.mask &= ~HDI_IMAGE;
}
else
{
hdi.iImage = nMode;
hdi.fmt |= HDF_BITMAP_ON_RIGHT|HDF_IMAGE;
}

pHeardCtrl->SetItem(nItem,&hdi);

return nMode;
}

//生成表头上"向上箭头"和"向下箭头"两个位图
CBitmap* CSortListCtrl::MakeColorBoxImage(BOOL bUp)
{
CClientDC dc(this);
CBitmap* pBitmap = new CBitmap;
pBitmap->CreateCompatibleBitmap(&dc,8,8);

CDC tempDC;
tempDC.CreateCompatibleDC(&dc);

CBitmap* pOldBitmap;
pOldBitmap = tempDC.SelectObject(pBitmap);

CPen penLight,penShadow,*pOldPen;

tempDC.FillSolidRect(0,0,8,8,RGB(0,0,255));

if(bUp == TRUE)
{
static POINT s_PtShadow[9]={{3,0},{3,1},{2,1},{2,2},{2,3},{1,3},{1,4},{1,5},{0,5}};
static POINT s_PtLight[9]={{4,0},{4,1},{5,1},{5,2},{5,3},{6,3},{6,4},{6,5},{7,5}};

penLight.CreatePen(PS_SOLID,1,RGB(255,255,255));

pOldPen = tempDC.SelectObject(&penLight);
tempDC.MoveTo(0,6);
tempDC.LineTo(7,6);
for(int i=0;i<9;i++)
{
tempDC.SetPixel(s_PtLight[i],RGB(255,255,255));
}

for(i=0;i<9;i++)
{
tempDC.SetPixel(s_PtShadow[i],RGB(100,100,100));
}

tempDC.SelectObject(pOldPen);
}
else if(bUp == FALSE)
{
static POINT s_PtShadow[9]={{0,1},{1,1},{1,2},{1,3},{2,3},{2,4},{2,5},{3,5},{3,6}};
static POINT s_PtLight[9]={{7,1},{6,1},{6,2},{6,3},{5,3},{5,4},{5,5},{3,5},{4,6}};

penShadow.CreatePen(PS_SOLID,1,RGB(100,100,100));

pOldPen = tempDC.SelectObject(&penShadow);
tempDC.MoveTo(7,0);
tempDC.LineTo(0,0);

for(int i=0;i<9;i++)
{
tempDC.SetPixel(s_PtLight[i],RGB(255,255,255));
}

for(i=0;i<9;i++)
{
tempDC.SetPixel(s_PtShadow[i],RGB(100,100,100));
}

tempDC.SelectObject(pOldPen);
}
else
{
//空白位图
}

tempDC.SelectObject(pOldBitmap);

return pBitmap;
}
yanfeiouc2009 2010-08-18
  • 打赏
  • 举报
回复
只有一列的时候没试过,因为需要用到多列数据啊。好像只要有重复值就不行。
另外老兄给的示例中
SortItems(..., ...);
是不是自己实现的排序方法啊,还是CListCtrl自带的方法?
iamshuke 2010-08-18
  • 打赏
  • 举报
回复
还有,如果只有一列也不能正确排序。
yanfeiouc2009 2010-08-18
  • 打赏
  • 举报
回复
多谢楼上兄弟的帮助,我在添加每一项的时候都用了

CString str;
str.Format(_T("%d"), i);
m_ListDB_sblx.InsertItem(i, str);
m_ListDB_sblx.SetItemData(i, (DWORD)i);

i是唯一的,但是还是不行。刚刚发现如果该列中没有重复的内容的话,排上最多两次就可以得到正确顺序,而有重复内容的话,排上几次就乱了。不知道是什么原因。
当时选CMFCListCtrl就是因为听说它排序方便,表头的三角号不用自己加。排序只需重载一个虚函数,在该函数中添加“按列号”比较两项大小就可以了。早知道这么麻烦就不用了。
iamshuke 2010-08-18
  • 打赏
  • 举报
回复
没用过CMFCListCtrl,但CListCtrl排序时,要先给每一项设上不同的ItemData,否则结果会不对,也许是同样的问题吧。

int i, nItemCount = GetItemCount();
DWORD *buf = new DWORD[nItemCount];

for(i=0; i<nItemCount; i++)
{
buf[i] = GetItemData(i);
SetItemData(i, i);
}

SortItems(..., ...);

for(i=0; i<nItemCount; i++)
{
SetItemData(i, buf[GetItemData(i)]);
}

delete []buf;

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧