CMyListCtrl
1. MyListCtrl.h
#pragma once #include <vector> #include "resource.h" // CMyListCtrl #ifdef DLL_IMPLEMENT #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif typedef unsigned int UINT; #define ID_LIST_SET_FONT 1001 #define ID_LIST_SAVE_ALL 1002 class DLL_API CMyListCtrl : public CListCtrl { struct SColumn { UINT index, order, width; TCHAR name[128]; }; std::vector<SColumn> m_vecColumn; COLORREF m_clrFore, m_clrBack; CFont m_font; CString m_strCfgFileName; int m_nSortCol;//排序列的索引,-1表示无排序列 bool m_bAscent;//true:升序 false:降序 CImageList m_imgList;//列表头的排序图标 DECLARE_DYNAMIC(CMyListCtrl) public: CMyListCtrl(); virtual ~CMyListCtrl(); protected: DECLARE_MESSAGE_MAP() public: // 用配置文件填充列 void FillColumn(LPCTSTR szConfigFileName); private: // 保存颜色信息到ini文件 void WriteColorInfoINI(const CString& strCfgFileName) { ::WritePrivateProfileStruct(_T("COLOR"), _T("color_fore"), &m_clrFore, sizeof(m_clrFore), strCfgFileName); } // 从ini配置文件获取颜色信息 void GetColorInfoINI(const CString& strCfgFileName) { ::GetPrivateProfileStruct(_T("COLOR"), _T("color_fore"), &m_clrFore, sizeof(m_clrFore), strCfgFileName); } // 保存字体信息到ini配置文件 void WriteFontInfoINI(const CString& strCfgFileName) { LOGFONT lf; GetFont()->GetLogFont(&lf); ::WritePrivateProfileStruct(_T("FONT"), _T("lf"), &lf, sizeof(lf), strCfgFileName); } // 从ini配置文件中获取字体信息 void GetFontInfoINI(const CString& strCfgFileName) { LOGFONT lf; if (::GetPrivateProfileStruct(_T("FONT"), _T("lf"), &lf, sizeof(lf), strCfgFileName)) { m_font.DeleteObject(); m_font.CreateFontIndirect(&lf); } else { m_font.DeleteObject(); m_font.CreateFont(20, 0, 0, 0, 400, 0, 0, 0, GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_ROMAN, _T("微软雅黑")); } } // 保存列信息到ini文件 void WriteColumnInfoINI(const CString& strCfgFileName) { CHeaderCtrl* pHeader = GetHeaderCtrl(); if (NULL == pHeader) return; int nCount = pHeader->GetItemCount(); if (0 == nCount) return; int* pOrder = new int[nCount]; GetColumnOrderArray(pOrder, nCount); CString strSection, strOrder, strColumnWidth; for (int i = 0; i < nCount; ++i) { strSection.Format(_T("%d"), i); strOrder.Format(_T("%d"), pOrder[i]); strColumnWidth.Format(_T("%d"), GetColumnWidth(i)); ::WritePrivateProfileString(strSection, _T("Order"), strOrder, strCfgFileName); ::WritePrivateProfileString(strSection, _T("Width"), strColumnWidth, strCfgFileName); } delete[] pOrder; } static int CALLBACK pfnSort(LPARAM lp1, LPARAM lp2, LPARAM lpSort); virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); public: afx_msg void OnSetFont(); afx_msg void OnSaveAll(); afx_msg void OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult); // 初始化一些变量,像m_imgList void InitListCtrl(); };
2. MyListCtrl.cpp
// MyListCtrl.cpp : 实现文件 // #include "stdafx.h" #define DLL_IMPLEMENT #include "MyListCtrl.h" // CMyListCtrl IMPLEMENT_DYNAMIC(CMyListCtrl, CListCtrl) CMyListCtrl::CMyListCtrl() { //m_nSortCol = -1; //m_bAscent = true; } CMyListCtrl::~CMyListCtrl() { } BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl) ON_COMMAND(ID_LIST_SET_FONT, OnSetFont) ON_COMMAND(ID_LIST_SAVE_ALL, OnSaveAll) ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, &CMyListCtrl::OnLvnColumnclick) END_MESSAGE_MAP() // CMyListCtrl 消息处理程序 // 用配置文件填充列 void CMyListCtrl::FillColumn(LPCTSTR szConfigFileName) { m_strCfgFileName = szConfigFileName; CString strSection; TCHAR szName[512] = { 0 }; for (UINT i = 0; true; ++i) { SColumn sC; strSection.Format(_T("%d"), i); sC.order = ::GetPrivateProfileInt(strSection, _T("Order"), -1, m_strCfgFileName); if (-1 == sC.order) break; sC.width = ::GetPrivateProfileInt(strSection, _T("Width"), -1, m_strCfgFileName); ::GetPrivateProfileString(strSection, _T("ColumnName"), _T("-1"), sC.name, sizeof(sC.name)/sizeof(sC.name[0]), m_strCfgFileName); m_vecColumn.push_back(sC); } //插入列 for (UINT i = 0; i < m_vecColumn.size(); ++i) { auto& c = m_vecColumn.at(i); InsertColumn(i, c.name, 0, c.width); } //按order排序 UINT nCount = m_vecColumn.size(); if (0 == nCount) return; int* arrOrder = new int[nCount]; for (UINT i = 0; i < nCount; ++i) { arrOrder[i] = m_vecColumn[i].order; } SetColumnOrderArray(nCount, arrOrder); delete[] arrOrder; //获取字体,设置字体 GetFontInfoINI(m_strCfgFileName); SetFont(&m_font); } BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { // TODO: 在此添加专用代码和/或调用基类 if (0 == wParam && ((NMHDR*)lParam)->code == NM_RCLICK) { POINT pt; GetCursorPos(&pt); CMenu menu; menu.CreatePopupMenu(); menu.AppendMenu(MF_STRING, ID_LIST_SET_FONT, _T("字体...")); menu.AppendMenu(MF_STRING, ID_LIST_SAVE_ALL, _T("保存所有设置")); menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this); } return CListCtrl::OnNotify(wParam, lParam, pResult); } void CMyListCtrl::OnSetFont() { LOGFONT lf; GetFont()->GetLogFont(&lf); CFontDialog dlg(&lf, CF_SCREENFONTS, NULL, this); if (IDOK == dlg.DoModal()) { m_font.DeleteObject(); m_font.CreateFontIndirect(&dlg.m_lf); SetFont(&m_font); } } void CMyListCtrl::OnSaveAll() { WriteFontInfoINI(m_strCfgFileName); WriteColumnInfoINI(m_strCfgFileName); } void CMyListCtrl::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult) { //LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); //// TODO: 在此添加控件通知处理程序代码 //*pResult = 0; //当点击不同的列表头时显示对应的排序图标 NM_LISTVIEW* p = (NM_LISTVIEW*)pNMHDR; int nSub = p->iSubItem;//点击的列的索引 CHeaderCtrl* pHeader = GetHeaderCtrl(); /* 方法1:用自己的图标或位图 //pHeader->SetImageList(&m_imgList); HDITEM hdi = { HDI_IMAGE | HDI_FORMAT }; if (nSub != m_nSortCol) {//点击不同列时,删除旧的列图标 if (m_nSortCol > -1) { HDITEM hdi = { HDI_FORMAT }; pHeader->GetItem(m_nSortCol, &hdi); hdi.fmt &= ~HDF_IMAGE ;//移除排序图标,win7下有问题,去不掉,加上 HDITEM hdi = { HDI_FORMAT };解决,看来开关mask很重要 pHeader->SetItem(m_nSortCol, &hdi); } m_nSortCol = nSub; } else {//点击相同列时,显示相反排序图标 m_bAscent = !m_bAscent; } pHeader->GetItem(nSub, &hdi); hdi.fmt |= HDF_IMAGE | HDF_BITMAP_ON_RIGHT; hdi.iImage = m_bAscent; pHeader->SetItem(nSub, &hdi); */ //方法2:用系统提供的排序图标 HDITEM hdi = { HDI_FORMAT }; if (nSub != m_nSortCol) {//点击不同列时,删除旧的列图标 if (m_nSortCol > -1) { pHeader->GetItem(m_nSortCol, &hdi); hdi.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); pHeader->SetItem(m_nSortCol, &hdi); } m_nSortCol = nSub; } else {//点击相同列时,显示相反排序图标 m_bAscent = !m_bAscent; } pHeader->GetItem(nSub, &hdi); hdi.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); hdi.fmt |= (m_bAscent ? HDF_SORTUP : HDF_SORTDOWN); pHeader->SetItem(nSub, &hdi); //排序前,要将所有列表项的索引保存到关联数据中 int i = GetItemCount(); while(i--) { SetItemData(i, i); } SortItems(pfnSort, (DWORD)this); // 排序第二个参数是比较函数的第三个参数 *pResult = 0; } int CALLBACK CMyListCtrl::pfnSort(LPARAM lp1, LPARAM lp2, LPARAM lpSort) { CMyListCtrl* p = (CMyListCtrl*)lpSort; CString s1 = p->GetItemText(lp1, p->m_nSortCol); CString s2 = p->GetItemText(lp2, p->m_nSortCol); if (p->m_bAscent) return s2 < s1; else return s1 < s2; } // 初始化一些变量,像m_imgList void CMyListCtrl::InitListCtrl() { m_imgList.Create(16, 16, ILC_COLOR32 | ILC_MASK, 2, 4); CBitmap b1, b2; b1.LoadBitmap(IDB_ASCENT); b2.LoadBitmap(IDB_DESCENT); m_imgList.Add(&b2, RGB(255, 255, 255)); m_imgList.Add(&b1, RGB(255, 255, 255)); CHeaderCtrl* pHeader = GetHeaderCtrl(); pHeader->SetImageList(&m_imgList); m_nSortCol = -1; m_bAscent = false; }
列配置文件 SetListing.ini
[0] order=0 width=193 columnName=column1 [1] order=1 width=193 columnName=column2 [2] order=2 width=235 columnName=column3 ...
在OnInitDialog中,添加
//成员变量 CMyListCtrl m_list; CRect rect; GetClientRect(rect); rect.bottom -= 70; m_list.Create(WS_VISIBLE | WS_CHILD | LVS_REPORT, rect, this, 10001); m_list.SetExtendedStyle(m_list.GetExStyle() | LVS_EX_FULLROWSELECT //| LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP); m_list.InitListCtrl(); CString strCfgPath = myFunctions::GetExeDir() + _T("\\SetListing.ini"); m_list.FillColumn(strCfgPath.GetString()); //m_list.InsertColumn(0, _T("jjj"), 0, 100); //m_list.InsertColumn(1, _T("jjj1"), 0, 100); //m_list.InsertColumn(2, _T("jjj2"), 0, 100); m_list.InsertItem(0, _T("123")); m_list.SetItemText(0, 1, _T("ss1")); m_list.SetItemText(0, 2, _T("dd1")); m_list.InsertItem(1, _T("222")); m_list.SetItemText(1, 1, _T("ss2")); m_list.SetItemText(1, 2, _T("dd2"));
系统默认的排序图标:
自己画的图标或位图:
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。