在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题
先谈谈我的问题吧!
在使用listctrl的过程中,我需要在列表头部添加checkbox,实现全选的功能。
经过网上资料的罗列,我找到了一个demo,使用的重绘的方法,在使用的过程中,我发现我的列表头无法绘出checkbox,于是开始找问题,最后发现是因为cheadctlcl这个重载的类里面的函数无法响应,
于是问题一步步逼近,为什么重载函数无法调用?cheadctlcl类的所有函数都无法响应。于是找了下问题,最后发现问题出在:
void CListCtrlEx::PreSubclassWindow()
{
// TODO: 在此添加专用代码和/或调用基类
//__super::PreSubclassWindow();
ModifyStyle(0,LVS_OWNERDRAWFIXED);
CListCtrl::PreSubclassWindow();
ModifyStyle(0,LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SORTDESCENDING );
CHeaderCtrl *pHeader = this->GetHeaderCtrl();
m_Header.SubclassWindow(pHeader->GetSafeHwnd());
}
调试发现,GetHeaderCtrl()调用返回老是为空。
于是就到网上找资料,找到下面这篇文章!!!
//////////////////////////////////////// 引用:http://wangqingyun84.blog.163.com/blog/static/7908361720119744913240////////////////////////////////////////////////
如果要自定义CListCtrl控件的表头, 比如最常用的双行显示文字, 或者要显示一些图片什么的, 最常用的方法就是自定义一个CHeaderCtrl类, 然后子类化. 步骤如下:
1. 先自定义一个CHeaderCtrl类的子类, 比如CHeaderCtrlEx. 接下来有两种方法
其一, 最暴力的方法是重写OnPaint()函数, 也就是给CHeaderCtrlEx添加ON_WM_PAINT()消息处理函数, 但这时所有的东西都要自已来绘制, 也就是整个的表头都要自已来绘制, 甚至包括中间的分隔线. 显然过于激进...
其二, 稍微温和点的方法. 使用HDI_FORMAT这个style. 实际上每当调用InsertColumn()插入一列时, 都可以指定该style, 那么绘制该列时就会调用OnDrawItem()函数, 当然了这是需要使用ON_WM_DRAWITEM()宏的, 在该消息响应函数中就可以自定义的绘制各种东西. 当然了每次绘制都是一个某列的表头. 这可不像CListCtrl的那个LVS_OWNERDRAWFIXED, 那个是一下绘制整个的一个item也就是一行.
2. 其次呢就是要子类化CListCtrl类的header control, 当然了我都是定义一个CListCtrl的子类, 假设名字叫做CListCtrlEx. 那么我们需要做的就是在该类中定义一个CHeaderCtrEx _headerCtrl, 之后呢选个合适的机会_headerCtrl.SubClassWindow(GetHeaderCtrl()->GetSafeHwnd())就可以了
我们的问题就是: 何时子类化, 也就是调用这条代码...
1. 网上好多地方都说是要在PreSubclassWindow()函数中...
2. 但一baidu这个GetHeaderCtrl(), 大家就有一个永恒的问题了: GetHeaderCtrl()返回值为NULL...
3. 有人说在PreSubclassWindow()中返回NULL, 但是在OnCreate()函数中就OK了...
但实际上好多的都用不同的方法解决了这个问题:
1. 最会逃避的方法就是用资源编辑器添加一个CListCtrl, 然后子类化成CListCtrlEx, 然后无论是在PreSubclassWindow()还是OnCreate()都没有任何的问题...
2. 有人说在PreSubclassWindow()中不行, 要在OnCreate()中才可以...
3. 但动态创建时还会有问题了, 也就是_listCtrl.Create(...), 用这种方法创建的控件, 在PreSubclassWindow()和OnCreate()时都还会有问题
4. 还有人极具创造力, 如,引用如下:
I noticed this too. If the list control is created as part of a dialog
template (for example) then the HWND of the header control exists inside of
the PreSubclassWindow function, whereas if the list control is created
dynamically (with a call to CListCtrl::Create()) then it does not.
I solved the problem by PostMessage'ing a user?defined message to myself
from inside of the PreSubclassWindow function. In the handler for the
user?defined message, the HWND for the header always exists, regardless of
how the list control was created, and I subclass the header from inside this
handler (and not from inside the PreSubclassWindow function).
I think it works because the user?defined message is posted at the end of
the message queue and is therefore handled at a later time, when everything
has "settled down" and both the list control and its header both have been
created.
也就是说, 这是在PreSubclassWindow()函数中没有直接调用GetHeaderCtrl(), 而是朝自己发了一个自定义消息, 然后添加该消息处理函数, 在收到该消息时再调用GetHeaderCtrl(), 这时"一般"都没有问题.
那么问题的关键是怎么呢???
很简单: 就是GetHeaderCtrl()只有在LVS_REPORT时才会返回表头对象, 其它style时肯定会返回空.
之所以在资源编辑器中静态的拖进去控件不会有问题, 可能是因为拖进去控件时就已经设置其style为LVS_REPORT, 通过实验可以发现, 如果不是LVS_REPORT时, 那么在PreSubclassWindow()函数中GetHeaderCtrl()依然会返回NULL.
唯一让人迷惑不解的是, 静态添加时, 如果不指定其style为LVS_REPORT, 那么虽然PreSubclassWindow()中是不可能的, 但OnCreate()中却一直GetHeaderCtrl()可能正常工作, 故, 不解...
所以, 解决方法为:
1. 通过静态的资源编辑器来添加控件, 那么如果是指定了LVS_REPORT时, 那么无论是在PreSubclassWindow()还是OnCreate()均没有问题, GetHeaderCtrl()都好使.
2. 通过静态的资源编辑器来添加控件, 那么如果没有指定LVS_REPORT, 则只能在OnCreate()中使用GetHeaderCtrl(), 在PreSubclassWindow()中是不可以的.
3. 最好的方法是, 在_listCtrl.Create()中务必要指定LVS_REPORT, 那么在调用了基类的CListCtrl::OnCreate()后, GetHeaderCtrl()必然可以工作...
或者更好一点, 就是在GetHeaderCtrl()之前, 先修改一下: ModifyStyle(0, LVS_REPORT), 这样最有把握..., 但是啊, 这种方法在PreSubclassWindow()中不是特别好用, 因为PreSubclassWindow()是在OnCreate()调用之前使用, 此时控件还不存在, 所以不好用
////////////////////////////////////////////////////////////////////////////////////////////////
最后的解决方法,是对clistctrlex类中重载OnCreate函数,在OnCreate函数中实现子类化就实现了功能。
在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题的更多相关文章
- 如何使用免费PDF控件从PDF文档中提取文本和图片
如何使用免费PDF控件从PDF文档中提取文本和图片 概要 现在手头的项目有一个需求是从PDF文档中提取文本和图片,我以前也使用过像iTextSharp, PDFBox 这些免费的PD ...
- 因为此控件已在 web.config 中注册并且与该页位于同一个目录中
在web.config文件配置了用户控件 <pages> <controls> <add tagPrefix="my" tagName="l ...
- 《ASP.NET1200例》解决母版页报错“内容控件必须是内容页中的顶级控件,或是引用母版页的嵌套母版页。”
VS2005下,添加了母版页这个控件,我们可以讲N个页面中共同的部分放在母版页来实现,并让WEB窗体集成自我们的母版页,就可以让我们的站点具有统一的风格了.在VS2005SP1之前的版本中,我们只能创 ...
- VS2010 Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)
步骤如下: 1. Chart控件(一)Chart控件在ASP.NET网站中的应用示例详解(C#语言)" title="VS2010 Chart控件(一)Chart控件在ASP.NE ...
- 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)
前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面. 奇葩 这两天遇到 ...
- MFC中给控件添加变量,DoDataExchange中
DoDataExchange函数其实是一项数据动态绑定技术.比如你在写动态按钮过程中须对按钮添加变量时,怎么添加?控件类已经写好了,其变量是已经固定的.你要添加新的变量就要用到DoDataExchan ...
- 列表控件ListBox关联的MFC中的类:CListBox
列表控件ListBox关联的MFC中的类:CListBox ######################################################## 1.在列表的结尾添加一项: ...
- WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
原文:WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探 最近因为项目需要,开始学习如何使用WPF开发桌面程序.使用WPF一段时间之后,感 ...
- qt 在ui界面添加控件后在cpp文件中无法调用?
问题:qt 在ui界面添加控件后在cpp文件中无法调用? 解决方法:在build选项中选择“重新build项目”,再次在cpp中调用添加的控件发现可以调用了. 还有一种情况导致添加控件后无法调用,就是 ...
随机推荐
- oracle各种常用管理sql及其他 ---待续
启动客户端工具:sqlplus /nolog 使用sysdba链接:conn / as sysdba; select * from dba_users; --查看数据库里面所有用户,前提是你是有dba ...
- go系列之数组
数组 数组是同一类型元素的集合.例如,整数集合 5,8,9,79,76 形成一个数组.Go 语言中不允许混合不同类型的元素,例如包含字符串和整数的数组.(译者注:当然,如果是 interface{} ...
- (部署)使用kubernetes的deployment进行RollingUpdate
rolling update,可以使得服务近乎无缝地平滑升级,即在不停止对外服务的前提下完成应用的更新. replication controller与deployment的区别 replicatio ...
- 《Effective Java》读书笔记四(泛型)
Java1.5发行版本中增加了泛型(Generic).在没有泛型之前,从集合中读取到的每一个对象都必须进行转换.如果有人不小心插入了错误的类型对象,在运行时的转换处理就会出错.有了泛型之后,可以告诉编 ...
- C#使用CodeDom动态加载cs文件
public static object Create(string path) { var provOptions = new Dictionary<string, string>(); ...
- hdoj 1698 Just a Hook 【线段树 区间更新】
题目大意:有一段链子.初始的时候是铜的(价值为1),n代表有n段(1~n),输入a, b, c三个数分别表示将从a到b的链子的价值改为c, 最后问你经过多次改变之后的总价值. 策略:这道题是简单的线段 ...
- scheduleOnce
//程序开始后延时2秒才开始addSprite函数 scheduleOnce(schedule_selector(Issue1305::addSprite), ); 转到定义: void CCNode ...
- 【Verilog】verilog实现奇数次分频
实现占空比为50%的N倍奇数分频:首先进行上升沿触发进行模N计数,计数到某一个值时进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%的奇数n分频时钟.再者 同时进行下降沿触发的 ...
- C++ string的用法
之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够.字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是 ...
- 关于ajax上传文件的流程 和选择图片立即显示
关键点: 1.制作一个表单..然后把上传字段附加到该表单中 2.制作一个框架..把表单的_target的属性指向该框架. 3.提交表单.. jQuery.extend({ createUploadIf ...