排序列表控件






4.82/5 (17投票s)
2003年11月18日
3分钟阅读

97488

3230
带有排序指示器的列表控件。
引言
首先,我要为文章中任何语法/拼写错误道歉。由于英语不是我的母语,我在打字时往往会犯很多错误。
CListViewCtrl
是一个不错的控件,主要用于报表模式。使用Windows资源管理器时,您可以看到它充满了文件。该控件还使用SortItems
函数支持排序机制。主要问题是没有排序指示器。
背景
在查看Code Project上的一些文章时,您可以找到两种解决方案。第一种解决方案是提供两个额外的位图资源 - 指示标题控件的箭头。第二种解决方案是自定义绘制的标题控件,能够绘制相应的箭头。
为什么要费心?Microsoft是如何绘制它的箭头的?Windows资源管理器是如何绘制自身的?
加载位图
查看一些文件后,我找到了解决方案。在shell32.dll中有两个位图。向上箭头是133,向下箭头是134。
要加载相应的位图,我们使用LoadImage
函数。由于大多数应用程序都将自身链接到shell32.dll,因此我们可以使用GetModuleHandle
函数来检索模块句柄。如果我们的应用程序没有将自身链接到shell32.dll,我们可以改用LoadLibrary
。
加载位图后,我们可以在标题控件上绘制它们,就像绘制其他位图一样。
排序
要使用列表控件进行排序,我们需要定义一个回调函数。为了避免手动执行此操作,我创建了一个结构的包装器,我的列表控件可以使用它。
使用代码
由于报表模式是一种结构,我们需要创建自己的类来保存相关信息。该类必须继承自CSortListViewCtrlItem
,并指定其类名作为模板参数。我们将使用一个表示单个文件的结构。
class CFileStruct : public CSortListViewCtrlItem<CFileStruct> { public: enum Field { Filename = 0, Size, Time }; CFileStruct(LPCTSTR szFilename,ULONGLONG nSize,FILETIME ftTime); int Compare(CFileStruct* pItem,int nField); CString Format(int nField); protected: CString m_szFilename; ULONGLONG m_nSize; FILETIME m_ftTime; };
构造函数初始化结构,而Format
函数只是将特定字段格式化为字符串。
重要的函数是Compare
。它根据指定的字段比较当前结构与另一个结构(您可以在maindlg.cpp中查看实现)。
其次,我们需要创建列表控件对象。CSortListViewCtrl
是一个模板类,它接受结构类型作为其参数。
CSortListViewCtrl<CFileStruct> m_List;
要为控件设置子类,我们可以调用SubclassWindow
或简单地使用运算符=
,它包装了子类化方法。
m_List=GetDlgItem(IDC_LIST1);
要使控件工作,我们需要动态创建新的结构(使用new
运算符),并使用SetItemData
函数将结构指针附加到列表项。我们不需要删除结构,因为控件在处理LVN_DELETEITEM
命令时会自动删除它。
控件应该自己处理所有排序。如果您想自己排序,可以调用Sort
函数。
要实现控件,必须遵循以下步骤
- 从
CSortListViewCtrlItem
派生您自己的类并实现Compare
函数。 - 使用您自己的结构作为其模板参数创建控件对象,并将其子类化到原始列表窗口。
- 使用
REFLECT_NOTIFICATIONS
宏反映来自控件父级的通知。
示例应用程序
示例应用程序创建一个列表控件,并用您Windows文件夹中的文件填充它。您可以按文件名、大小或时间戳排序文件。还有一个工具提示支持,显示有关单个文件的全部信息。
最后说明
源代码按原样提供。您可以自由使用它并根据需要修改它。如果您发布任何使用它的应用程序,我将感谢您给我发电子邮件(只是为了我的虚荣心:))。
历史
2003年11月18日 - 首次公开发布。