zoukankan      html  css  js  c++  java
  • 在对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函数中实现子类化就实现了功能。

  • 相关阅读:
    QLPreviewController来预览文件
    Camera360SDK
    实现 JSON + Jquery+.Net ajax功能
    showModalDialog传值
    web方式AJAX调用
    CRM4.0多个实体关联查询
    用javascript 动态添加部门和人员
    GridView中使用超连接
    根据订单号查询出订单附属实体
    sql 常用聚合函数
  • 原文地址:https://www.cnblogs.com/lihaiping/p/cheadctrl.html
Copyright © 2011-2022 走看看