ListCtrl - 一个具有 Windows Vista 风格项选择功能的 WTL 列表控件
一个灵活的 WTL 列表控件,支持 Windows Vista 风格的选择和单元格编辑。
引言
我来自 MFC 背景,我认为是时候踏上一段新的技术旅程,学习如何开发炫酷的 .NET 应用程序,并用我新获得的 C# 知识给大家留下深刻印象。我在这款时髦的新平台上已经取得了长足的进步,从学习 CLR 的内部机制到 C# 语言语法。然而,我有一个小小的、挥之不去的问题。它不能让我兴奋。为什么它不能让我兴奋很令人费解,因为我交谈过的每个人以及我读到的几乎所有东西似乎都认为 .NET 框架是有史以来最伟大的发明——就像人们突然想到为每个人节省自己切面包的麻烦一样——也许是控件方面的问题,或者我需要“放手”。
总之,这些闲话应该放在另一篇文章里;然而,这可以很好地引出我是如何发现 WTL 的,以及为什么我无法放弃 C++ 的习惯,转而在 .NET 的世界里追求名利。顺便说一句,我还应该指出,我热爱 C++,WTL 确实让我感到兴奋。
背景
在学习使用 WTL 的过程中,我决定开始移植一个我很久以前用 MFC 写过的列表控件,并在过程中进行改进。这篇文章就是我努力的成果——又一个支持许多功能的列表控件,但无疑不能完全满足你的所有需求。但那样还有什么乐趣呢!
特点
- Vista 风格的项选择。
- 主题化或经典 UI 支持。
- 项或子项选择。
- 子项编辑、组合框和日期/时间。
- 超链接、复选框(普通和三态)以及进度条(主题化和实心)。
- 标题列拖放重新排序。
- 内置列排序支持。
- 酷炫的 Alpha 混合分组选择框。
- 双缓冲无闪烁绘制(WTL 自带)。
- 平滑滚动(带减速)。
- 标题提示(不要与工具提示混淆,但工具提示也支持)。
- 一切看起来都很漂亮(这不算是一个特性,但我还是想提一下)。
- 嵌入式数据结构或类支持(稍后讨论)。
- 数据源覆盖(稍后也会讨论)。
附加
您可能还会对我的树控件感兴趣,它与 `CListCtrl` 的绘制风格相辅相成:TreeCtrl - 一个具有 Windows Vista 风格项选择的 WTL 树控件。
如何使用 CListCtrl
首先,我认为有必要解释一下子项和列的格式/标志,这些可以用来控制文本在列表控件中的显示和编辑方式。项格式可以设置在列级别,这意味着该列下的所有子项共享相同的格式,或者设置在单独的子项级别,这将覆盖列格式。在演示中可以看到列/子项格式的一个例子,“Column 5”具有 `ITEM_FORMAT_PROGRESS` 的列级别格式,但它已被单个子项覆盖,以演示其他格式。
我鼓励您尝试演示;然而,既然这是 CodeProject,我猜您可能已经这样做了。对于那些想要更多细节的人,以下是使用通用 `CListCtrl` 入门所需的基本函数
void SetImageList(
CImageList& ilItemImages
)
描述
为列表控件项分配图像列表。
参数
- `ilItemImages` - 图像列表的引用。
void AddColumn( CListColumn& listColumn ) void AddColumn( LPCTSTR lpszText, int nWidth = 0, int nImage = ITEM_IMAGE_NONE, BOOL bFixed = FALSE, UINT nFormat = ITEM_FORMAT_NONE, UINT nFlags = ITEM_FLAGS_NONE )
描述
向列表控件添加一列。
参数
- `listColumn` - 描述列详细信息的结构的引用。
- `lpszText` - 列标题字符串。
- `nWidth` - 列的宽度(以像素为单位)。
- `nImage` - 图像列表中用于在列标题中显示的图像索引。
- `bFixed` - `TRUE` 表示固定列宽。
- `nFormat` - 描述该列所有子项的格式
- `ITEM_FORMAT_NONE` - 默认,只读子项。
- `ITEM_FORMAT_EDIT` - 可编辑子项。
- `ITEM_FORMAT_DATETIME` - 日期/时间子项。
- `ITEM_FORMAT_COMBO` - 组合框子项。
- `ITEM_FORMAT_CHECKBOX` - 2 状态复选框子项。
- `ITEM_FORMAT_CHECKBOX_3STATE` - 3 状态复选框子项。
- `ITEM_FORMAT_HYPERLINK` - 超链接(可点击)子项。
- `ITEM_FORMAT_PROGRESS` - 进度指示器子项。
- `ITEM_FORMAT_CUSTOM` - 自定义子项。
- `nFlags` - 描述列格式类型的位掩码
- `ITEM_FLAGS_NONE` - 无格式标志(默认)。
- `ITEM_FLAGS_LEFT` - 左对齐列标题和子项文本。
- `ITEM_FLAGS_RIGHT` - 右对齐列标题和子项文本。
- `ITEM_FLAGS_CENTRE` - 居中对齐列标题和子项文本。
- `ITEM_FLAGS_READ_ONLY` - 列中的子项是只读的(适用于 `ITEM_FORMAT_CHECKBOX[_3STATE]` 或 `ITEM_FORMAT_DATETIME`)。
- `ITEM_FLAGS_EDIT_UPPER` - 编辑文本强制转换为大写(`ITEM_FORMAT_EDIT` 或 `ITEM_FORMAT_COMBO` + `ITEM_FLAGS_COMBO_EDIT`)。
- `ITEM_FLAGS_EDIT_NUMBER` - 编辑文本是数字(`ITEM_FORMAT_EDIT` 或 `ITEM_FORMAT_COMBO` + `ITEM_FLAGS_COMBO_EDIT`)。
- `ITEM_FLAGS_EDIT_FLOAT` - 编辑文本是浮点数(`ITEM_FORMAT_EDIT` 或 `ITEM_FORMAT_COMBO` + `ITEM_FLAGS_COMBO_EDIT`)。
- `ITEM_FLAGS_EDIT_NEGATIVE` - 编辑文本允许负数(`ITEM_FLAGS_EDIT_NUMBER` 或 `ITEM_FLAGS_EDIT_FLOAT`)。
- `ITEM_FLAGS_EDIT_OPERATOR` - 数字文本可以以“>”、“<=”等开头(`ITEM_FLAGS_EDIT_NUMBER` 或 `ITEM_FLAGS_EDIT_FLOAT`)。
- `ITEM_FLAGS_COMBO_EDIT` - 组合框包含编辑控件(`ITEM_FORMAT_COMBO`)。
- `ITEM_FLAGS_DATE_ONLY` - 只显示或编辑日期(`ITEM_FORMAT_DATETIME`)。
- `ITEM_FLAGS_TIME_ONLY` - 只显示或编辑时间(`ITEM_FORMAT_DATETIME`)。
- `ITEM_FLAGS_DATETIME_NONE` - 允许在日期/时间选择器中显示“无”(`ITEM_FORMAT_DATETIME`)。
- `ITEM_FLAGS_PROGRESS_SOLID` - 进度条以实心风格绘制(`ITEM_FORMAT_PROGRESS`)。
int AddItem( CListItem< TData >& listItem ) int AddItem( LPCTSTR lpszText, int nImage = ITEM_IMAGE_NONE, UINT nFormat = ITEM_FORMAT_NONE, UINT nFlags = ITEM_FLAGS_NONE )
描述
向列表控件添加一个项。
参数
- `listItem` - 描述所有项详细信息的结构的引用。
- `lpszText` - 第一个子项文本。
- `nImage` - 图像列表中用于在第一个子项中显示的图像索引(参见 `SetImageList`)。
- `nFormat` - 描述第一个子项的格式(参见 `AddColumn` 获取描述)。
- `nFlags` - 描述子项格式类型的位掩码(参见 `AddColumn` 获取描述)。
BOOL SetItemText( int nItem, int nSubItem, LPCTSTR lpszText )
描述
设置子项文本。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `lpszText` - 子项文本。
BOOL SetItemDate( int nItem, int nSubItem, SYSTEMTIME& stItemDate )
描述
设置子项日期(用于 `ITEM_FORMAT_DATETIME` 子项)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `stItemDate` - `SYSTEMTIME` 结构的引用。
BOOL SetItemComboIndex( int nItem, int nSubItem, int nIndex )
描述
设置子项组合框项选择(用于 `ITEM_FORMAT_COMBO` 子项)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `nIndex` - 组合框列表中要设置的索引。
BOOL SetItemCheck( int nItem, int nSubItem, int nCheckValue )
描述
设置子项复选框状态(用于 `ITEM_FORMAT_CHECKBOX` 和 `ITEM_FORMAT_CHECKBOX_3STATE` 子项)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `nCheckValue` - 表示复选框状态的数字
0
- 未选中(或 3 状态下的未定义)。1
- 已选中(或 3 状态下的“勾选”)。-1
- 3 状态下的“叉”(不适用于 2 状态复选框)。
BOOL SetItemImage( int nItem, int nSubItem, int nImage )
描述
设置子项图像。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `nImage` - 图像列表中用于在子项中显示的图像索引(参见 `SetImageList`)。
BOOL SetItemFormat( int nItem, int nSubItem, UINT nFormat, UINT nFlags = ITEM_FLAGS_NONE ) BOOL SetItemFormat( int nItem, int nSubItem, UINT nFormat, UINT nFlags, CListArray < CString >& aComboList )
描述
设置子项格式(覆盖列格式)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `nFormat` - 描述子项的格式(参见 `AddColumn` 获取描述)。
- `nFlags` - 描述子项格式类型的位掩码(参见 `AddColumn` 获取描述)。
- `CListArray < CString >& aComboList` - 用于填充组合框的字符串数组(用于 `ITEM_FORMAT_COMBO`)。
BOOL SetItemFont( int nItem, int nSubItem, HFONT hFont )
描述
设置子项字体(覆盖标准字体)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `hFont` - GDI 字体的句柄。
BOOL SetItemColours( int nItem, int nSubItem, COLORREF rgbBackground, COLORREF rgbText )
描述
设置子项背景和文本颜色(覆盖标准颜色)。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
- `rgbBackground` - 子项背景的 RGB 值。
- `rgbText` - 子项文本的 RGB 值。
void ShowThemed(
BOOL bShowThemed = TRUE
)
描述
覆盖默认的标题和选择绘制(适用于 XP+)。
参数
- `bShowThemed` - `TRUE` = 绘制主题化的标题和选择;`FALSE` = 经典模式。
void SetSmoothScroll(
BOOL bSmoothScroll = TRUE
)
描述
在分页或逐行滚动时平滑滚动列表。
参数
- `bSmoothScroll` - `TRUE` = 平滑滚动;`FALSE` = normal 滚动。
void SetBackgroundImage(
HBITMAP hBackgroundImage,
BOOL bTileImage = FALSE
)
描述
设置背景位图图像。
参数
- `hBackgroundImage` - 要设置为背景的位图句柄。
- `bTileImage` - `TRUE` = 平铺图像;`FALSE` = 居中绘制图像。
void ShowHeader(
BOOL bShowHeader = TRUE
)
描述
显示或隐藏列表标题。
参数
- `bShowHeader` - `TRUE` = 显示列表标题;`FALSE` = 隐藏列表标题。
void ShowHeaderSort(
BOOL bShowSort = TRUE
)
描述
显示排序(标题)箭头并支持列排序。
参数
- `bShowSort` - `TRUE` = 支持列排序;`FALSE` = 隐藏排序箭头。
void SetSingleSelect(
BOOL bSingleSelect = TRUE
)
描述
只允许选择一个(禁用多选和组选择)。
参数
- `bSingleSelect` - `TRUE` = 只允许单项选择;`FALSE` = 支持多选和组选择。
void SetFocusSubItem(
BOOL bFocusSubItem = TRUE
)
描述
支持子项焦点或整个项的选择。
参数
- `bFocusSubItem` - `TRUE` = 支持子项焦点;`FALSE` = 整个项焦点。
如何使用 CListCtrlData< class TData >
`CListCtrl` 支持 `SetItemData` 和 `GetItemData`;这些函数用于设置和检索列表项的 `DWORD` 值,您可以根据需要使用这些值。但是,您可能会发现直接集成(或嵌入)您的数据结构或类到控件中更有用。为此,您需要模板类 `CListCtrlData`(演示应用程序中包含了一个示例)。以下函数可用于访问这些数据:
BOOL SetItemData(
int nItem,
TData& tData
)
描述
为项分配数据。
参数
- `nItem` - 项的索引(从零开始)。
- `tData` - 数据结构或类的引用(类型在模板类声明中定义)。
BOOL GetItemData(
int nItem,
TData& tData
)
描述
从项检索数据。
参数
- `nItem` - 项的索引(从零开始)。
- `tData` - 数据结构或类的引用(类型在模板类声明中定义)。
如何使用 CListImpl
有时,仅使用通用控件是不够的。您可能希望
- 向控件添加新功能,
- 自定义绘制,或者
- 完全控制列表数据源。
由于 `CListImpl` 的设计中清晰地分离了接口和数据源,您可以简单地派生一个类并覆盖数据访问器函数,从而完全掌控数据源,包括数据的存储和访问方式。在演示中,您会找到 `CListUserData` - 这个类存储了它自己的 `CUserProfiles`(示例类)数组,并在 `GetItemText` 和 `GetItemImage` 中返回相关的文本或图像。在派生类中,**唯一**必需的函数是
int GetItemCount()
描述
返回数据源中的项数。
CString GetItemText( int nItem, int nSubItem )
描述
返回子项文本。
参数
- `nItem` - 项的索引(从零开始)。
- `nSubItem` - 子项的索引(从零开始)。
历史
- 1.0 -(2006 年 3 月 10 日)首次发布。
- 1.1 -(2006 年 3 月 13 日)VS2005 小 bug 修复 - 感谢 chengang。
- 1.2 -(2006 年 3 月 17 日)修正了在 VS2005 下编译时出现的“访问冲突”,并添加了 `ShowThemed`。
- 1.3 -(2006 年 3 月 27 日)添加了组选择时的自动滚动 - 感谢 Slaham 的建议。
- 1.4 -(2006 年 4 月 5 日)添加了平滑滚动(`SetSmoothScroll`)并修复了 Windows 2000 的问题 - 感谢 ihanz123。
- 1.5 -(2006 年 4 月 10 日)添加了背景图像支持和 `SetItemComboIndex` - 感谢 MyRock 的建议。
最后
尽管这个列表控件很棒,但我恐怕不能独享所有功劳,因为它利用了来自各种来源的代码,包括 CodeProject 上发布的文章。正如您所料,创意和代码片段被借鉴并无情地扭曲应用到这个项目中,并在此过程中采用了我的编码风格。对于任何认出自己的作品但未被署名的,我深表歉意(请给我发邮件,我会修改我的致谢),但在此我感谢以下人员为我指明了正确的方向。