在对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中调用添加的控件发现可以调用了. 还有一种情况导致添加控件后无法调用,就是 ...
随机推荐
- redis实践:用户注册登录功能
本节将使用PHP和Redis实现用户注册登录功能,下面分模块来介绍具体实现方法. 1.注册 需求描述:用户注册时需要提交邮箱.登录密码和昵称.其中邮箱是用户的唯一标识,每个用户的邮箱不能重复,但允许用 ...
- Java:集合,Map接口框架图
Java集合大致可分为Set.List和Map三种体系,其中Set代表无序.不可重复的集合:List代表有序.重复的集合:而Map则代表具有映射关系的集合.Java 5之后,增加了Queue体系集合, ...
- 在ModelSim中添加Xilinx仿真库
在ModelSim中添加Xilinx仿真库 说明: l ModelSim一定要安装在不带空格的目录下,即不要安装在“Program Files”目录下.如作者是安装在D:\softwares\Mode ...
- 前端 JS,localStorage/sessionStorage、cookie 及 url 等实现前台数据共享、传输
需求是这样的:需要统计用户公司某款产品用户的回馈情况,美工给的设计多个psd,每个页面里面都有一个选择题,让用户选择自己的答案,最后经过几次选择之后在最后一个页面统一提交到后台!所以这里引出的技术需求 ...
- UnityTestTools測试工具
由于工作关系,要了解Unity上的測试工具,该工具基于Nunit框架.通过查阅资料了解到在Unity5.3中做出了一些改变,自带的仅仅剩下单元測试工具,假设想用其它的工具比方断言.集成測试,就须要前往 ...
- java.net.Socket/java.net.ServerSocket-TCP Socket编程
TCP 的 Java 支持 协议相当于相互通信的程序间达成的一种约定,它规定了分组报文的结构.交换方式.包含的意义以及怎样对报文所包含的信息进行解析,TCP/IP 协议族有 IP 协议.TCP 协议和 ...
- python学习之str.lstrip()
str.lstrip([chars]) 删除从开头开始指定的字符串,然后返回结果字符串. >>> '://www.example.com'.lstrip('w://') '.exam ...
- 李洪强iOS之集成极光推送三iOS集成指南
李洪强iOS之集成极光推送三iOS集成指南 SDK说明 适用版本 本文匹配的 SDK版本:r2.1.5 以后.查看最近更新了解最新的SDK更新情况.使用Xcode 6及以上版本可以使用新版Push S ...
- IOS7的蛋疼各种收集
------------------ ios7基于viewController隐藏状态条:通过ViewController重载方法返回枚举值的方法来控制状态栏的隐藏和样式.首先,需要在Info.pli ...
- 七、如何在Java中高效检查一个数组是否含有一个值
如何检查一个数组(非排序的)是否包含特定的值.这是个非常有用或经常被在Java中使用.这是个在Stack Overflow中高得票的问题.在已经高得票的答案中,有许多不同的处理方法,但是时间的复杂度非 ...