65.9K
CodeProject 正在变化。 阅读更多。
Home

CListCtrl 和分组行

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (34投票s)

2008 年 9 月 15 日

CPOL

3分钟阅读

viewsIcon

251687

downloadIcon

8822

启用 MFC 列表控件中类别的示例

引言

Microsoft 的 CListCtrl 支持在网格中显示数据,但也支持数据分组。本文将演示如何激活 CListCtrl 的分组功能。

该演示应用程序允许您体验如何使用分组。只需右键单击列标题,即可根据该标题对数据进行分组。

screenshot.png

背景

Microsoft 通过发布 Windows XP 扩展了 CListCtrl 的分组支持。这项新功能并没有得到太多的推广,并且在功能上也受到限制(无法折叠组)。后来,Windows Vista 发布时,该实现得到了进一步扩展,增加了更多功能(折叠、页脚、副标题等)。

已经有一些 .NET 文章描述了如何在 Windows XP 中使用分组

还有 MSDN - Windows Vista 控制增强,其中描述了 Windows Vista 中的一些新内容。

我第一次真正看到一个有用的应用程序使用这种分组功能是在 TortoiseSVN 1.5 中。

如何在 CListCtrl 中激活分组

在激活分组之前,必须满足一些条件

  • 操作系统必须支持 Common Controls ver. 6(Windows XP/Vista 及更高版本)
  • 应用程序必须通过其清单启用 Common Controls ver. 6
  • 应用程序必须使用至少设置为 0x0501_WIN32_WINNT 进行编译

当满足上述要求时,我们可以像这样创建一个组

LRESULT CListCtrl_Category_Groups::CreateSingleGroup(int nIndex, 
                  int nGroupId, const CString& strHeader)
{
    EnableGroupView( TRUE );
 
    LVGROUP lg = {0};
    lg.cbSize = sizeof(lg);
    lg.iGroupId = nGroupId;
    lg.state = LVGS_NORMAL;
    lg.mask = LVGF_GROUPID | LVGF_HEADER | LVGF_STATE | LVGF_ALIGN;
    lg.uAlign = LVGA_HEADER_LEFT;
 
    // Header-title must be unicode (Convert if necessary)
    lg.pszHeader = strHeader.GetBuffer();
    lg.cchHeader = strHeader.GetLength();
    nGroupId = InsertGroup(nIndex, &lg );
    if (nGroupId==-1)
        return nGroupId;
 
    // Insert all current items into this group
    for(int nRow = 0; nRow < GetItemCount(); ++nRow)
    {
        LVITEM lvItem = {0};
        lvItem.mask = LVIF_GROUPID;
        lvItem.iItem = nRow;
        lvItem.iSubItem = 0;
        lvItem.iGroupId = nGroupID;
        SetItem( &lvItem );
    }
}

上面的示例代码创建一个具有以下属性的新组

  • 该组将被插入到 CListCtrl 内部组列表中 nIndex 的位置。
  • 该组将获得外部标识符 nGroupId
  • 该组标题将变为文本字符串 strHeader

Windows XP 中的限制

在 Windows XP 上使用组时,我们会发现以下内容缺失

  • 无法询问 CListCtrl 内部组列表中有多少个组。建议我们自己跟踪创建的组。
  • 无法遍历 CListCtrl 内部组列表中的组。建议我们自己跟踪创建的组。
  • 无法询问 CListCtrl 鼠标光标当前是否位于组上方。相反,我们必须进行大量猜测。
  • 无法更改组的状态,使其变为折叠状态。

这些限制已通过 Windows Vista 解决,同时还添加了以下功能

  • 可以将任务链接附加到组
  • 可以提供位于标题文本正下方的副标题文本
  • 可以为组提供页脚文本

使用源代码

提供的源代码演示了如何激活不同的分组功能

  • InsertGroupHeader() - 创建一个新组。 CListCtrl::InsertGroup() 的包装器。
  • SetRowGroupId() - 将行添加到现有组。带有 LVIF_GROUPIDCListCtrl::SetItem() 的包装器。
  • GroupByColumn(int nCol) - 为指定列中每个唯一的单元格文本创建一个新组。
  • SortColumn(int nCol) - 对从指定列生成的组进行排序。 CListCtrl::SortGroups() 的包装器。
  • GroupHitTest(const CPoint& point) - 尝试查找给定鼠标点下方的组。
  • CheckEntireGroup() - 启用 CListCtrl 扩展样式 LVS_EX_CHECKBOXES 后,此方法将更改整个组的复选框状态。

它还演示了如何使用一些新的 Windows Vista 功能

  • CollapseAllGroups() - 循环访问所有组并使它们折叠。带有 LVGS_STATECListCtrl::SetGroupInfo() 的包装器。
  • SetGroupTask() - 更改组的任务链接。当用户单击任务链接时,它将生成一个 LVN_LINKCLICK 消息。
  • SetGroupSubtitle() - 更改组的副标题。
  • SetGroupFooter() - 更改组的页脚。

历史

  • 2008-09-16 - 文章的首次发布
  • 2009-09-28 - 从 CGridListCtrlEx 反向移植错误修复,并且在启动时,它现在按第 3rd 列对行进行分组
  • 2011-07-27 - 修复了在 Vista\Win7 上使用并使用 _WIN32_WINNT >= 0x0600 编译时 GroupHitTest() 中的错误
© . All rights reserved.