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_,这三个属性, ...
随机推荐
- nginx结合fastcgi
1.首先安装nginx,这里采用编译安装 useradd -M -s /sbin/nologin nginx 安装一些依赖包: yum -y install pcre-devel libxslt-de ...
- 20144303 《Java程序设计》第九周学习总结
20144303 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 一.JDBC入门: JDBC全名Java DataBase Connectivity,是java联机数据库 ...
- linux 第三周
linux内核目录结构 arch目录包括了所有和体系结构相关的核心代码.它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录.PC机一 ...
- JAVA国际化输出日期格式
1.建议控制台程序 使用 IntelliJ IDEA 创建 MAVEN项目, 不选别的选项,则为控制台程序. (其它方式创建的控制台程序可能编译不过) 2.源码如下: import java.tim ...
- powershell如何查看以及设置环境变量
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment ...
- 使用maven命令进行打包,部署项目到远程仓库
如果要部署项目到远程仓库, 方法一:配置pom.xml: <distributionManagement> <repository> <id>releases< ...
- R 中的哪些命令或者包让你相见恨晚?--转载知乎
https://www.zhihu.com/question/24501195 节选: 看了这么多答案,觉得 Hadley Wickhamhad.co.nz 在R使用者的地位好高啊.其实我也觉得Had ...
- Springboot依赖注入笔记
结合Autowired和Service注解 public interface IUser { void say(); } @Service public class Student implement ...
- bzoj 3039: 玉蟾宫 单调栈或者悬线法求最大子矩阵和
3039: 玉蟾宫 Time Limit: 2 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 有一天,小猫rainbow ...
- 讲一下numpy的矩阵特征值分解与奇异值分解
1.特征值分解 主要还是调包: from numpy.linalg import eig 特征值分解: A = P*B*PT 当然也可以写成 A = QT*B*Q 其中B为对角元为A的特征值的对 ...