MFC CListControl 点击列头排序的实现
SetItemData可以为每一行绑定一个DWORD类型的变量。用GetItemData可以获得这个变量。
举个例子,假设CListCtrl中你需要显示某个数据表中的记录,该表有个流水号主键ID,一般这个ID值本身没有什么意义,用户也不需要看,因此在CListCtrl的可见列中,你不需要显示。但往往做具体查询等操作时,你又需要用这个ID来完成。这时,用SetItemData将其绑定到每一行,将非常方便,用户操作哪一行,则用GetItemData可以得到对应记录的ID,直接用来做操作。
SetItemData未绑定对象,可直接绑定行号进行排序。
排序类
ListCtrl_Sortable.h
#pragma once
class CListCtrl_Sortable : public CListCtrl
{
public:
bool m_Ascending;
int m_SortCol;
DECLARE_MESSAGE_MAP();
afx_msg BOOL OnHeaderClick(NMHDR* pNMHDR, LRESULT* pResult);
void PreSubclassWindow();
public:
CListCtrl_Sortable()
:m_Ascending(false)
,m_SortCol(-1)
{}
int GetColumnData(int col) const;
void SetSortArrow(int col, bool ascending);
bool IsAscending() const { return m_Ascending; }
void ResetSortOrder();
virtual bool SortColumn(int columnIndex, bool ascending);
static int g_columnIndex;
static bool g_ascending;
};
ListCtrl_Sortable.cpp
#include "stdafx.h"
#include "CListCtrl_Sortable.h"
#include "Resource.h"
#include <shlwapi.h>
int CListCtrl_Sortable::g_columnIndex = 0;
bool CListCtrl_Sortable::g_ascending = false;
BEGIN_MESSAGE_MAP(CListCtrl_Sortable, CListCtrl)
ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnHeaderClick) // Column Click
END_MESSAGE_MAP()
namespace {
bool IsThemeEnabled()
{
HMODULE hinstDll;
bool XPStyle = false;
bool (__stdcall *pIsAppThemed)();
bool (__stdcall *pIsThemeActive)();
// Test if operating system has themes enabled
hinstDll = ::LoadLibrary("UxTheme.dll");
if (hinstDll)
{
(FARPROC&)pIsAppThemed = ::GetProcAddress(hinstDll, "IsAppThemed");
(FARPROC&)pIsThemeActive = ::GetProcAddress(hinstDll,"IsThemeActive");
::FreeLibrary(hinstDll);
if (pIsAppThemed != NULL && pIsThemeActive != NULL)
{
if (pIsAppThemed() && pIsThemeActive())
{
// Test if application has themes enabled by loading the proper DLL
hinstDll = LoadLibrary("comctl32.dll");
if (hinstDll)
{
DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hinstDll, "DllGetVersion");
::FreeLibrary(hinstDll);
if (pDllGetVersion != NULL)
{
DLLVERSIONINFO dvi;
ZeroMemory(&dvi, sizeof(dvi));
dvi.cbSize = sizeof(dvi);
HRESULT hRes = pDllGetVersion ((DLLVERSIONINFO *) &dvi);
if (SUCCEEDED(hRes))
XPStyle = dvi.dwMajorVersion >= 6;
}
}
}
}
}
return XPStyle;
}
LRESULT EnableWindowTheme(HWND hwnd, LPCWSTR app, LPCWSTR idlist)
{
HMODULE hinstDll;
HRESULT (__stdcall *pSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
HANDLE (__stdcall *pOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
HRESULT (__stdcall *pCloseThemeData)(HANDLE hTheme);
hinstDll = ::LoadLibrary("UxTheme.dll");
if (hinstDll)
{
(FARPROC&)pOpenThemeData = ::GetProcAddress(hinstDll, TEXT("OpenThemeData"));
(FARPROC&)pCloseThemeData = ::GetProcAddress(hinstDll, TEXT("CloseThemeData"));
(FARPROC&)pSetWindowTheme = ::GetProcAddress(hinstDll, TEXT("SetWindowTheme"));
::FreeLibrary(hinstDll);
if (pSetWindowTheme && pOpenThemeData && pCloseThemeData)
{
HANDLE theme = pOpenThemeData(hwnd,L"ListView");
if (theme!=NULL)
{
VERIFY(pCloseThemeData(theme)==S_OK);
return pSetWindowTheme(hwnd, app, idlist);
}
}
}
return S_FALSE;
}
}
BOOL CListCtrl_Sortable::OnHeaderClick(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW* pLV = reinterpret_cast<NMLISTVIEW*>(pNMHDR);
SetFocus(); // Ensure other controls gets kill-focus
int colIndex = pLV->iSubItem;
if (m_SortCol==colIndex)
{
m_Ascending = !m_Ascending;
}
else
{
m_SortCol = colIndex;
m_Ascending = true;
}
if (SortColumn(m_SortCol, m_Ascending))
SetSortArrow(m_SortCol, m_Ascending);
return FALSE; // Let parent-dialog get chance
}
void CListCtrl_Sortable::SetSortArrow(int colIndex, bool ascending)
{
if (IsThemeEnabled())
{
#if (_WIN32_WINNT >= 0x501)
for(int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i)
{
HDITEM hditem = {0};
hditem.mask = HDI_FORMAT;
VERIFY( GetHeaderCtrl()->GetItem( i, &hditem ) );
hditem.fmt &= ~(HDF_SORTDOWN|HDF_SORTUP);
if (i == colIndex)
{
hditem.fmt |= ascending ? HDF_SORTDOWN : HDF_SORTUP;
}
VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) );
}
#endif
}
else
{
UINT bitmapID = m_Ascending ? IDB_DOWNARROW : IDB_UPARROW; //IDB_DOWNARROW,表示向下箭头IDB位图;IDB_UPARROW,表示向上箭头IDB位图
for(int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i)
{
HDITEM hditem = {0};
hditem.mask = HDI_BITMAP | HDI_FORMAT;
VERIFY( GetHeaderCtrl()->GetItem( i, &hditem ) );
if (hditem.fmt & HDF_BITMAP && hditem.fmt & HDF_BITMAP_ON_RIGHT)
{
if (hditem.hbm)
{
DeleteObject(hditem.hbm);
hditem.hbm = NULL;
}
hditem.fmt &= ~(HDF_BITMAP|HDF_BITMAP_ON_RIGHT);
VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) );
}
if (i == colIndex)
{
hditem.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
hditem.hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(bitmapID), IMAGE_BITMAP, 0,0, LR_LOADMAP3DCOLORS);
VERIFY( hditem.hbm!=NULL );
VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) );
}
}
}
}
void CListCtrl_Sortable::PreSubclassWindow()
{
CListCtrl::PreSubclassWindow();
// Focus retangle is not painted properly without double-buffering
#if (_WIN32_WINNT >= 0x501)
SetExtendedStyle(LVS_EX_DOUBLEBUFFER | GetExtendedStyle());
#endif
SetExtendedStyle(GetExtendedStyle() | LVS_EX_FULLROWSELECT);
SetExtendedStyle(GetExtendedStyle() | LVS_EX_HEADERDRAGDROP);
EnableWindowTheme(GetSafeHwnd(), L"Explorer", NULL);
}
void CListCtrl_Sortable::ResetSortOrder()
{
m_Ascending = true;
m_SortCol = -1;
SetSortArrow(m_SortCol, m_Ascending);
}
// The column version of GetItemData(), one can specify an unique
// identifier when using InsertColumn()
int CListCtrl_Sortable::GetColumnData(int col) const
{
LVCOLUMN lvc = {0};
lvc.mask = LVCF_SUBITEM;
VERIFY( GetColumn(col, &lvc) );
return lvc.iSubItem;
}
// 比较函数
static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// 从参数中提取所需比较lc的两行数据
int row1 = (int) lParam1;
int row2 = (int) lParam2;
CListCtrl* lc = (CListCtrl*)lParamSort;
CString lp1 = lc->GetItemText(row1,CListCtrl_Sortable::g_columnIndex);
CString lp2 = lc->GetItemText(row2,CListCtrl_Sortable::g_columnIndex);
// 文字型比较
if (CListCtrl_Sortable::g_ascending)
return lp1.CompareNoCase(lp2);
else
return lp2.CompareNoCase(lp1);
return 0;
}
bool CListCtrl_Sortable::SortColumn(int columnIndex, bool ascending)
{
//排序
g_columnIndex = columnIndex;
g_ascending = ascending;
int count = GetItemCount();
for (int i=0;i<count;i++)
{
SetItemData(i,i); // 每行的比较关键字,此处为列序号(点击的列号),可以设置为其他 比较函数的第一二个参数
}
SortItems(MyCompareProc, (DWORD_PTR)this);
return true;
}
//IDB_DOWNARROW,表示向下箭头IDB位图;IDB_UPARROW,表示向上箭头IDB位图。
SetItemData绑定对象排序。
如果SetItemData绑定的数据是一个对象时,需要在SortColumn函数的比较函数中做处理。通过GetItemData读取对象,遍历CListCtrl所有行,与对象比较,找到某两行。然后再获取这两行对应列的文本,进行比较排序。
ListCtrl_Sortable_ItemObject.h
#pragma once
#include "listctrl_sortable.h"
class CListCtrl_Sortable_ItemObject : public CListCtrl_Sortable
{
public:
CListCtrl_Sortable_ItemObject(void);
virtual ~CListCtrl_Sortable_ItemObject(void);
virtual bool SortColumn(int columnIndex, bool ascending);
};
ListCtrl_Sortable_ItemObject.cpp
#include "StdAfx.h"
#include "ListCtrl_Sortable_ItemObject.h"
CListCtrl_Sortable_ItemObject::CListCtrl_Sortable_ItemObject(void)
{
}
CListCtrl_Sortable_ItemObject::~CListCtrl_Sortable_ItemObject(void)
{
}
//比较函数
static int CALLBACK ItemObjectCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// 从参数中提取所需比较lc的两行数据
void * pRow1 = (void *) lParam1;
void * pRow2 = (void *) lParam2;
if(pRow1 == NULL || pRow2 == NULL)
return 0;
CListCtrl* lc = (CListCtrl*)lParamSort;
void * pTempObject = NULL;
int nItemCount = lc->GetItemCount();
int nn = 0,nRow1 = -1,nRow2 = -1;
for(nn=0; nn<nItemCount; nn++)
{
pTempObject = (void *)lc->GetItemData(nn);
if(pTempObject == pRow1)
{
nRow1 = nn;
}
else if(pTempObject == pRow2)
{
nRow2 = nn;
}
if(nRow1 != -1 && nRow2 != -1)
{
break;
}
}
if(nRow1 == -1 || nRow2 == -1)
return 0;
CString lp1 = lc->GetItemText(nRow1,CListCtrl_Sortable_ItemObject::g_columnIndex);
CString lp2 = lc->GetItemText(nRow2,CListCtrl_Sortable_ItemObject::g_columnIndex);
// 文字型比较
if (CListCtrl_Sortable_ItemObject::g_ascending)
return lp1.CompareNoCase(lp2);
else
return lp2.CompareNoCase(lp1);
return 0;
}
bool CListCtrl_Sortable_ItemObject::SortColumn(int columnIndex, bool ascending)
{
//排序
g_columnIndex = columnIndex;
g_ascending = ascending;
SortItems(ItemObjectCompareProc, (DWORD_PTR)this);
return true;
}
MFC CListControl 点击列头排序的实现的更多相关文章
- C++ 简单实现MFC ListControl 点击列头排序
说明: SetItemData可以为每一行绑定一个DWORD类型的变量.用GetItemData可以获得这个变量.举个例子,假设CListCtrl中你需要显示某个数据表中的记录,该表有个流水号主键ID ...
- [WPF]ListView点击列头排序功能实现
[转] [WPF]ListView点击列头排序功能实现 这是一个非常常见的功能,要求也很简单,在Column Header上显示一个小三角表示表示现在是在哪个Header上的正序还是倒序就可以了. ...
- MFC listcontrol 分列 添加行数据 点击列头排序
适用于 对话框程序 1.在工具箱中拖出 ListControl,然后右键-属性,view-Report 让你的ListControl变成这幅模样! 2.添加ListControl控件的control类 ...
- DataWindow.NET 控件 实现点击列头排序
1.定义字段 Boolean ib_SetSort = true; string is_SortType = " ...
- easyui datagrid 点击列表头排序出现错乱的原因
之前我的导师,也就是带我的同事,使用datagrid,发现点击列表头排序出现乱序,按理说只有顺序和逆序两种排序结果.因为他比较忙,当时没解决,把排序禁掉了,后来又要求一定要排序,所以他交给我. 一开始 ...
- datagridview 点击列标题排序
开发winform中,平时经常用到数据列表,我们大多选用datagridview,但是此控件本身没有排序的功能.参阅网上资料.留下标记,以后备用. datagridview的数据显示一般是通过数据绑定 ...
- jqgrid 点击列头的超链接或按钮时,不触发列排序事件
接上篇文章:jqgrid 将列头设置为超链接或按钮 如果在列头设置了超链接或按钮,在点击超链接或按钮时会触发列的排序事件. 原由:点击超链接/按钮会触发排序的冒泡事件 解决方法:点击超链接/按钮时,阻 ...
- DataGridView使用技巧十三:点击列头实现升序和降序排序
DataGridView 列有三种排序模式.每一列的排序模式是通过该列的 SortMode 属性指定的,该属性可以设置为以下的 DataGridViewColumnSortMode 枚举值之一. Da ...
- 交叉报表列头排序时遇到的oracle问题—oracle ORA-12704:字符集不匹配、varchar2转化为nvarchar2字符缺失、case when else后的字符类型要一致
在做交叉报表列头的排序时,遇到这三个问题,下面具体来说一下. 设计的数据库的表结构如图1所示: 图1 要处出来student_name_,s.grade_,s.subject_name_,这三个属性, ...
随机推荐
- 简单的dos命令
cd .. 进入上一层目录cd /.. 进入当前盘所有根目录d: 进入d盘dir 查看下一级目录d:>d:\abc.txt 新建一个文档hostname 主机名SET 查看环境变 ...
- ubuntu下apt-get的配置文件是哪个
答:在/etc/apt/apt.conf 这个配置文件里可以指定使用代理,如: Acquire::https::proxy "http://myproxy.com:8080/";
- python sort dict 总结
python中的dict是不能排序的,只有对dict的representation进行排序,例如list或者tuple 排序肯定会用到sorted函数,那么我们就来讲一下sorted函数. sorte ...
- IE8下打印内容缩小问题
去掉启动缩小字体填充的设置项勾选 来自为知笔记(Wiz)
- [PyTorch]PyTorch中模型的参数初始化的几种方法(转)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本文目录 1. xavier初始化 2. kaiming初始化 3. 实际使用中看到的初始化 3.1 ResNeXt,de ...
- 【分类】AlexNet论文总结
目录 0. 论文链接 1. 概述 2. 对数据集的处理 3. 网络模型 3.1 ReLU Nonlinearity 3.2 Training on multiple GPUs 3.3 Local Re ...
- 【链接】SpringBoot启动错误
[错误解决]SpringBoot启动错误 https://blog.csdn.net/Small_Mouse0/article/details/78551900
- 51Nod 1433 0和5(9的倍数理论)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1433 思路: 数论中关于9的倍数的理论:若是一个数能被9整除,则各位数之 ...
- ubuntu如何U盘启 动制作
先到出 U盘的位置, 方法有很多,terminal 用root权限,采用fdisk -f 命令 unmount /dev/sdb -I //U盘拨出 sdb为U盘挂载的位置 mkfs.fat /dev ...
- 英语每日阅读---5、VOA慢速英语(翻译+字幕+讲解):美国人口普查局表示美国人受教育程度提升
英语每日阅读---5.VOA慢速英语(翻译+字幕+讲解):美国人口普查局表示美国人受教育程度提升 一.总结 一句话总结: a.Thirty-four percent - college degree: ...