码迷,mamicode.com
首页 > 其他好文 > 详细

CGridListCtrlEx

时间:2015-01-18 09:19:05      阅读:475      评论:0      收藏:0      [点我收藏+]

标签:c++   mfc   clistctrl   cgridlistctrlex   说明   

原文出处: http://www.codeproject.com/Articles/29064/CGridListCtrlEx-Grid-Control-Based-on-CListCtrl

      另见: https://code.google.com/p/cgridlistctrlex


转载请注明出处!

简介

微软的ClistCtrl提供了以报表的形式在表格中显示数据的功能,但是功能有限, 我们不得不自己扩充一些功能, 如下:

本文演示如何使用CGridListCtrlEx,它实现了上述所有功能,同时保持Windows XP/ Vista的样子.

技术分享

SubVersion(svn) 版本见 Google Code - CGridListCtrlEx ,他同样有 Doxygen Documentation.

背景介绍

有很多CListCtrl的高级扩展控件,其中有一个 Enhanced List Control (CGfxListCtrl).这个niubility的控件提供了上述所有功能,但是不支持XPVista.找一个好用的替代实为不易:

  • MFC Grid Control -不继承自CListCtrl因此不受限于此,但也意味着它将不会获得任何微软提供给CListCtrl的好处和特性.
  • Ultimate Grid -很像MFC列表控件,不继承自CListCtrl.曾经收费,现在免费.
  • CQuickList -非常接近一个完美的替代品,但是它很难扩展数据呈现方式.并且需要LVS_OWNERDATA属性,这使其排序比较困难.
  • XListCtrl -同样是一个非常完美的CListCtrl,但难以扩展数据呈现方式.并且不支持LVS_OWNERDATA.收费.
  • Another Report List Control -简单易用,但缺乏除使用CEdit以外的方法编辑数据,也没有子项导航功能.
  • CListCtrlEx -实现了很多功能并有完善的文档.原先需要LVS_OWNERDRAWFIXED,现在改成自绘.自绘和所有者绘制二者结合的方式使代码略显复杂,它同样也不支持LVS_OWNERDATA.

CGridListCtrlEx插入了一个抽象层,称之为”column traits”(列特性),用来绘制和编辑单元格.Microsoft又扩展了CListCtrl,希望CGridListCtrlEx能继续工作.

如何使用CGridListCtrlEx

CGridListCtrlEx 试图还原一个真实的CListCtrl,不会替换任何CListCtrlalready已经提供的特性.这意味着我们可以用CGridListCtrlEx 直接替换CListCtrl 而不必做任何额外操作.

建议不要直接使用CGridListCtrlEx ,而是派生一个CGridListCtrlEx 的子类.这将使其更容易兼容以后的任何更新.

编辑单元格/子项

默认情况下,当向CGridListCtrlEx插入一列,会被配置为只读不可编辑的.通过调用CGridListCtrlEx::InsertColumnTrait(),我们可以提供一个CGridColumnTrait 类来指定使用什么类型的编辑器.

CGridColumnTrait* pTrait = new CGridColumnTraitEdit;
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(),LVCFMT_LEFT, 100, nCol, pTrait);
当编辑一个项时,一个标准LVN_ENDLABELEDIT消息会被发送至CListCtrl.CGridListCtrlEx收到这个消息时,它会自动调用虚方法CGridListCtrlEx::OnEditComplete(),使派生类确认输入,并可能会更新底层数据模型.

使用Combo-box编辑单元格/子项

调用CGridListCtrlEx::InsertColumnTrait(),,我们还可以提供一个CGridColumnTrait 类使之像CComboBox一样工作.

CGridColumnTraitCombo* pTrait = new CGridColumnTraitCombo;
pTrait->AddItem(0, "Hello");
pTrait->AddItem(1, "Goodbye");
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(),LVCFMT_LEFT, 100, nCol, pTrait);
上边的代码展示了,当插入列时指定CComboBox .如果想动态提供CComboBox ,我们可以覆盖CGridListCtrlEx::OnEditBegin().使用dynamic_cast<>得到安全类型,调用列特性方法CGridColumnTraitCombo::LoadList(),或者直接使用返回的CComboBox编辑器.

如果想获取已选中的CComboBox项的itemdata,可以重载CGridListCtrlEx::OnEditComplete()并检查pLVDI->item.lParam.该值需要被另外保存, 因为它不能保存在CListCtrl的本地数据模型中.

行排序

默认情况下,GridListCtrlEx 会对所有列启用排序,它会执行一个简单的文本比较.也可以重载CGridColumnTrait::OnSortRows()根据列特性实现自定义排序.

配置列特性使用数量比较排序:

CGridColumnTraitEdit* pTrait = new CGridColumnTraitEdit;
pTrait->SetSortFormatNumber(true); // Numeric column
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(),LVCFMT_LEFT, 100, nCol, pTrait);
列特性CGridColumnTraitDateTime 会自动比较日期排序.

我们也可以选择重载方法,那么我们所要做的仅仅是选择一个正正确方式执行排序.参见CListCtrl 行排序.

显示提示工具

默认情况下,CGridListCtrlEx 仅显示单元格内容提示.如果想显示一些其他提示信息,可以CGridListCtrlEx::OnDisplayCellTooltip()重载方法.

格式化单元格/子项

如果想要改变前景/背景颜色,或者字体样式(粗体,斜体, 下划线), 可以重载CGridListCtrlEx::OnDisplayCellColor()方法和CGridListCtrlEx::OnDisplayCellFont()方法.

bool MyGridCtrl::OnDisplayCellColor(int nRow, int nCol, COLORREF& textColor,COLORREF& backColor)
{
   if (nRow == 3 && nCol == 3)
   {
      textColor = RGB(0,255,0);
      backColor = RGB(0,0,255);
      return true;  // I want to override the color of this cell
   }
   return false;  // Use default color
}

显示单元格/子项图片

默认情况下,CGridListCtrlEx 启用扩展样式LVS_EX_SUBITEMIMAGES,但是仍需使用CListCtrl::SetImageList()附加一个CImageList .

附加完图片后,可以将CImageList中的索引绑定到单元格/子项上.这可以通过CGridListCtrlEx::SetCellImage()完成,或者如果使用了I_IMAGECALLBACK,那么图片索引号会从重载的CGridListCtrlEx::OnDisplayCellImage()返回.

默认情况下,CGridListCtrlEx 也启用了扩展样式LVS_EX_GRIDLINES,这会导致子项图片和边框重叠.可以通过使用16像素中的15像素(第一像素透明)来解决这个问题.

当使用子项图片并在XP下运行应用程序,或使用经典样式时, 当选中一行会显示白色背景. 这问题可以使用CGridRowTraitXP解决.

m_ListCtrl.SetDefaultRowTrait(new CGridRowTraitXP);

复选框支持

CListCtrl supports checkboxes for the labelcolumn out of the box. Just apply the extended styleLVS_EX_CHECKBOXES:

只要应用扩展样式LVS_EX_CHECKBOXES,便可支持标题栏复选框:

m_ListCtrl.SetExtendedStyle(m_ListCtrl.GetExtendedStyle()| LVS_EX_CHECKBOXES);

切记不要使用InsertHiddenLabelColumn(),它会隐藏标题栏和复选框.可以使用GetCheck() / SetCheck()来检索/修改复选框的值.

如果想要在多列使用复选框,可以使用CGridColumnTraitImage(和它的特性).

// Appendsthe unchecked/checked state images to the list control image list
int nStateImageIdx = CGridColumnTraitImage::AppendStateImages(m_ListCtrl, m_ImageList);
m_ListCtrl.SetImageList(&m_ImageList, LVSIL_SMALL);
// Createsan image column, that can switch between the 2 images
CGridColumnTrait* pTrait = new CGridColumnTraitImage(nStateIdx, 2);
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(),LVCFMT_LEFT, 20, nCol, pTrait);
for(int i=0; i < m_ListCtrl.GetItemCount();++i)
         m_ListCtrl.SetCellImage(i,nCol, nStateImageIdx);   // Uncheck item
当使用SetImageList()分配一个CImageList ,标签栏会自动显示图片列.不能禁用此行为,但可以使用InsertHiddenLabelColumn()隐藏标题栏.

CGridColumnTraitImage 使用单元格图片绘制复选框,因此它不能在同一列同时拥有单元格图片和复选框.可以使用GetCellImage() / SetCellImage()来获取或设置checked/unchecked状态.

CGridColumnTraitImage 支持根据复选框是否选中排序,使用CGridColumnTraitImage::SetSortImageIndex() 启用这个功能.

CGridColumnTraitImage 也支持切换所有选中行的复选框状态.使用CGridColumnTraitImage::SetToggleSelection()启用这个功能.

超链接支持

超链接列可以将单元格文本显示为超链接,单击可以调用外部应用程序例如浏览器(http)或邮箱客户端(mailto)打开超链接.

The CGridColumnTraitHyperLink allows oneto supply a prefix (and suffix) for the celltext, which allows one to add extraprotocol details without it being displayed:

CGridColumnTraitHyperLink 允许我们为单元格文本(celltext)提供一个前缀(和后缀),它允许我们添加额外的协议细节而不显示它.

CGridColumnTraitHyperLink* pHyperLinkTrait = new CGridColumnTraitHyperLink;
pHyperLinkTrait->SetShellFilePrefix(_T("http://en.wikipedia.org/wiki/UEFA_Euro_"));
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(),LVCFMT_LEFT, 100, nCol, pHyperLinkTrait);
也可以使用 CGridColumnTraitHyperLink::SetShellApplication()指定启动一个自定义应用程序,代替仅靠协议前缀启动的默认应用程序.

超链接也可以被用来模拟按键.点击它会发送LVN_ENDLABELEDIT通知,父窗体可以将其当作单击一个按钮处理.

更改行高

CGridListCtrlEx 使用自定义绘制(customdraw),所以只有如下解决方案可用:

·        指定一个CImageList ,图片高度便是行高.

·        行高会跟随单元格字体改变而改变.CGridListCtrlEx::SetCellMargin()使用这种方法增大单元格字体,但保持整行字体不变.

更改空标记文本

CGridListCtrlEx 不包含任何项时,它会显示标记文本以表示该列表为空.

使用CGridListCtrlEx::SetEmptyMarkupText()来更改这个标记文本.如果指定空文本, 它会像一个普通CListCtrl.

If using CGridListCtrlGroups, it willinstead react to LVN_GETEMPTYMARKUP if runningon Windows Vista.

当运行在Vista系统时,如果使用CGridListCtrlGroups,它会对LVN_GETEMPTYMARKUP作出反应.

载入和保存列宽和位置

CViewConfigSectionWinApp 提供了存储列宽,位置的能力, 无论列是否被显示. CGridListCtrlEx添加了所有可用列后,使用CGridListCtrlEx::SetupColumnConfig()分配一个CViewConfigSectionWinApp的实例,它将通过CWinApp恢复上次保存的列配置.

m_ListCtrl.SetupColumnConfig(new CViewConfigSectionWinApp("MyList"));
如果在应用程序多处使用了CGridListCtrlEx ,那么应该确保在每个地方单独创建一个CViewConfigSectionWinApp.

OLE拖放

CGridListCtrlEx 可以同时作为OLE拖动源和OLE放置目标.这允许CGridListCtrlEx 和其他窗体和应用程序之间拖拽操作.

CGridListCtrlEx 支持通过拖拽重新排列行顺序.这通过一种特殊排序方法实现,所以项不会被删除/插入.

要实现你自己的特殊拖拽行为,无论是重载OnDropSelf()还是OnDropExternal(),取决与你要做什么处理.

要控制拖拽时的拖拽源,重载OnDisplayToDragDrop().

CGridColumnTrait是如何工作的

CGridListCtrlEx 规避所有令人讨厌的关于如何显示和编辑数据的细节,这些细节由CGridColumnTrait 类处理,如果想要修改数据的现实方式, “只需创建一个新CGridColumnTrait .

当插入一列时,我们可以为其指定一个CGridColumnTrait .当需要绘制或编辑该列中的单元格时,CGridListCtrlEx 将激活相应的CGridColumnTrait.

CGridColumnTrait 包含一些被称为元数据(meta-data)的特殊成员.这些成员能被用于你自己派生自CGridListCtrlEx的类中,这样我们便可很容易的为一个列添加额外属性.

CGridColumnTrait中继承时,我们需要考虑下列情况:

  • 如果执行自绘操作,我们必须也处理选中项和焦点项的着色.
  • 如果执行编辑操作,我们必须确保当编辑器失去焦点时关闭编辑器,当编辑结束时发送一个LVN_ENDLABELEDIT消息.

CGridRowTrait Work是如何工作的

CGridRowTrait CGridColumnTrait 异曲同工,只不过它操作的是行而不是列.这对于修改所有列的现实行为特别有用.

使用代码

源码包含下列类:

  • CGridListCtrlEx -扩展的 CListCtrl
  • CGridListCtrlGroups - 支持分组的CGridListCtrlEx 
  • CGridColumnTrait -指定列特性(column-trait)接口
  • CGridColumnTraitText -实现单元格格式化
  • CGridColumnTraitImage -通过在图片间切换实现单元格编辑(可以模拟复选框)
  • CGridColumnTraitEdit -使用CEdit实现单元格编辑
  • CGridColumnTraitCombo -使用CComboBox实现单元格编辑
  • CGridColumnTraitDateTime -使用CDateTimeCtrl实现单元格编辑 
  • CGridColumnTraitHyperLink -实现单元格作为超链接的行为
  • CGridRowTrait -指定行特性接口
  • CGridRowTraitText -实现行格式化
  • CGridRowTraitXP -当使用XP样式(XP-style),实现子项图像背景图绘制
  • CViewConfigSection - (persisting)列设置的抽象接口
  • CViewConfigSectionWinApp -实现能在多列设置间切换的接口

需要做的事

CGridListCtrlEx 尽量不执行任何自绘(drawing itself).这意味着下列特性/bug不会获得很多关注:

  • 进度条支持需要一个绘制整个单元格的CGridColumnTrait .

实例化绘制整个单元格的CGridColumnTrait ,可以从ListCtrl - A WTL List Control with Windows Vista Style Item Selection中剽窃/借鉴.

非常欢迎向该项目贡献代码.

历史

Version 1.0 (2008-09-04) First release

Version 1.1 (2008-09-18)

    • 添加了分组支持 -CGridListCtrlGroups
    • 添加了编辑器 -CDateTimeCtrl 
    • 修复了当使用经典XP样式(XP-style)时的绘制bug
    • 修复了选中子项的图片背景色(不再是白色)
    • 修复了当左右滚动时表格边框消失的bug
    • 当列表没有元素时标示空表
    • 扩展了CComboBox 编辑器,这样它根据内容自动调整下拉框大小

Version 1.2 (2008-09-24)

    • CGridListCtrlXP 替换为CGridRowTraitXP
    • 修复了一些报告的bug

Version 1.3 (2008-10-09)

    • 修复了在CView中使用时的扩展样式
    • 修复了当使用快捷键(Shift+F10)时右键菜单(context-menu)定位bug
    • 修复了VC6编译错误

Version 1.4 (2008-11-07)

    • 添加了剪切板支持,以复制选中单元格/行的内容
    • Callback改名为 OnDisplay”, 这样它看起来符合MFC命名规则.
    • 修复了一些报告的bug

Version 1.5 (2009-03-29)

    • 添加了列管理器 -CGridColumnManager
    • 添加了在VC6上使用platform SDK时的分组支持
    • 添加了不同VS版本的项目文件
    • 通过Doxygen改进了文档

Version 1.6 (2009-09-13)

    • 添加了OLE拖拽支持
    • 添加了当使用LVS_OWNERDATA,checkboxLVS_EX_CHECKBOX样式支持
    • 添加了键盘搜索配合LVS_OWNERDATA更好的支持
    • 修复了一些bug

Version 1.7 (2009-12-12)

    • 添加了CGridColumnTraitImage,可以为任何列模拟复选框编辑
    • OnTraitEditBegin()改名为OnEditBegin()
    • OnTraitEditComplete()改名为 OnEditComplete()
    • OnTraitCustomDraw() 改名为 OnCustomDrawCell()
    • 修复了一些bug(大多是行和单元格配色相关的)

Version 1.8 (2010-10-01)

    • 为所有编辑器列特性构造了一个基类CGridColumnTraitImage ,他们都可以模拟复选框
    • 实现了多选列表复选框支持,所有选中项的复选框可以同时改变状态.
    • 通过基础列特性实现了最小和最大列宽
    • 修复了一些bug

Version 1.9 (2011-05-30)

    • CGridColumnTrait::OnSortRows的参数从字符串改为LVITEM 
    • CGridColumnConfig 改名为CViewConfigSection
    • 去掉CGridColumnManager ,LoadState/SaveState移入CGridListCtrlEx (重大更改)

Version 2.0 (2012-05-01)

    • 添加了CDateTimeCtrl 编辑器(DTS_APPCANPARSE)复制/粘贴支持
    • 现在当按列分组时,点击表头排序对分组列起作用.( When having grouped by column, then column headerclick now sorts instead of grouping by column)
    • 默认行排序不区分大小写
    • 修复了使用鼠标撤销单元格编辑器所做更改的bug(使用右键菜单复制/粘贴)
    • 修复了一些编译期警告和小bug

Version 2.1 (2012-06-20)

    • 修复了2.0中描述的bug,列表项分组不再在XP下工作.
    • 提高了列表项分组排序性能,尤其是在Vista/Win7+.
    • 添加了新的列特性CGridColumnTraitHyperLink,可以以网址的形式显示单元格文本.更新了演示程序以展示该新特性.
    • 添加了新的列特性CGridColumnTraitMultilineEdit,可以编辑包含新行的单元格文本(依然显示在单行中)
    • 修复了一些bug

Version 2.2 (2012-11-11)

    • 现在CGridColumnTraitCombo 可以设置在编辑开始时显示下拉框(SetShowDropDown)
    • 现在所有列特性编辑器可以设置在首次鼠标点击时启动编辑器(SetSingleClickEdit)
    • CGridColumnTraitHyperLink 会在鼠标点击时发送LVN_ENDLABELEDIT通知到父窗体(仿真按键点击).
    • 子项使用的复选框状态图标,已经通过禁止图片缩放在Win7/8得到了改进.
    • 修复了一些bug

许可(License)

这篇文章,以及任何相关的源代码和文件,遵循The Code Project Open License (CPOL)

 

CGridListCtrlEx

标签:c++   mfc   clistctrl   cgridlistctrlex   说明   

原文地址:http://blog.csdn.net/ren0065/article/details/42824043

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!