当前位置:C++技术网 > 资讯 > [MFC] CListCtrl控件如何实现 实时(准时) 获取复选框选中与未选中的状态

[MFC] CListCtrl控件如何实现 实时(准时) 获取复选框选中与未选中的状态

更新时间:2016-08-12 19:41:05浏览次数:1+次

CListCtrl m_List;
m_List.SetExtendedStyle(LVS_EX_CHECKBOXES)
可以设置每行项目都有复选框,但是该如何能 实时(准时) 地获取选中与未选中的状态?
我自己解决方法分别是:
1.创建一条线程,每秒循环调用 m_List.GetCheck(nIndex) 函数,进行异步检测复选框的状态,但是此方法不太好,万一 CListCtrl 项目有所变更,而我的线程刚好在循环当中,就会造成冲突现象,且这个方法太消耗资源.
2.重载消息回调函数 PreTranslateMessage(MSG* pMsg),下条件断点获取项目更改消息,此方法虽好,但是获取的是十进制数值,无疑增加了代码的阅读性.
请问这个问题该如何解决?

C++技术网解答:

    这个问题想复杂了。其实实现可以很简单。不过看提出的自己的解决方法,能感觉到你经验还是比较丰富的。这两天问题比较多,下班后都熬夜在解答问题,还写了教程文章,所以你的问题,现在才开始解答,请见谅。

    使用一个线程来不同的获取状态,确实是一个不错的选择。在其他很多地方的实时状态显示之类的,都是用额外的线程做的。不过,多线程编程中,一定要考虑到公共资源的互斥操作,以免破坏了资源,从而引发程序逻辑错误,得到不想得到的结果。Windows下多线程的编程问题,推荐你看《Windows核心编程》。

    前些时间写了一部分的连载Windows核心编程的教程,请搜索 Windows核心编程入门 ,对于开始学习核心编程有很大帮助。


    第二个方法使用PreTranslateMessage(MSG* pMsg),说明你也知道消息的拦截处理,这个确实不错。很多界面程序的功能,都可以通过拦截处理实现。但是因为你拦截的位置太超前了,所以和控件本身的关联不是很大,所以还是没有得到满意的效果。

    鉴于你的编程经验和编程水平都不错,所以主要问题在于思路。所以这里就给你提供一个改进的实现方法,就不写具体的实现代码了。如果你解决了问题,可以将这个点分享给大家哦。

    CListCtrl控件虽然也是窗口,但是已经是一个系统处理过的窗口了。所以,我们要处理CListCtrl的消息,最好是基于系统处理过的消息处理,也就是控件的事件机制。事件机制就是系统处理了控件的标准窗口后二次形成的窗口消息,对于窗口彪西而言,属于衍生的窗口消息,只是对话框、控件等都作为了系统的标准组件,所以这些消息也就成为了二次标准窗口消息,即对话框消息。

    对于控件来讲,也就是系统将控件接受到的消息处理后,再以消息的形式转发出来,我们处理这个消息,就可以处理控件的界面,实现功能。MFC封装了对话框控件的消息处理,最后以事件的形式给我们提供重载。CWnd基类中,只是做默认处理,如果我们重载了对应的处理函数,我们就可以将我们的逻辑加在控件中了。

    要想实时检测CListCtrl控件的每一行的复选状态,并不需要实时去查询,也不需要去拦截每一个消息。这些都可以实现,但是性能不足,实现也麻烦。我们要分析,这些状态何时会发生变化,也就是我们精准的定位到发生变化的位置,然后再做处理。这样,我们处理的位置和控件越近,得到控件的信息越多,越方便处理,而且只有在状态变化的时候,才会通知其他地方更新显示。

    而控件的状态发生,就发生在控件的点击。我们不会自己去发消息改变,如果是自己发,我们也知道状态发生了改变,哪些有改变。所以,我们只要处理好CListCtrl的成员函数CListCtrl::HitTest就可以实现精准的处理,效果是最好的。

    CListCtrl::HitTest的函数声明如下:


int HitTest(
   LVHITTESTINFO* pHitTestInfo 
) const;
int HitTest(
   CPoint pt,
   UINT* pFlags = NULL 
) const;

     第一种形式是得到一个HITTESTINFO结构体指针,这个结构体包含了点击的位置和点击结果的信息。而第二种形式则直接以两个参数来接受。第一参数为点击的坐标点,第二个为点击的结果。点击的结果为一个标志,这个标志就可以确定你到底点击到控件的哪些位置了,比如点击到了控件的客户区的靠上的区域,还是左边、右边、下面,或者点击到列表项图标、列表项文字、列表头部等等,每一个标志对应一个预定的位置。这些标志就是一个整数,预先定义的一些值被定义为一些宏,方便我们使用。点击结果位置的标志宏有这些:

LVHT_ABOVE
LVHT_BELOW
LVHT_NOWHERE
LVHT_ONITEMICON
LVHT_ONITEMLABEL
LVHT_ONITEMSTATEICON
LVHT_TOLEFT
LVHT_TORIGHT
LVHT_EX_GROUP_HEADER
LVHT_EX_GROUP_FOOTER
LVHT_EX_GROUP_COLLAPSE
LVHT_EX_GROUP_BACKGROUND
LVHT_EX_GROUP_STATEICON
LVHT_EX_GROUP_SUBSETLINK
LVHT_EX_GROUP
LVHT_EX_ONCONTENTS
LVHT_EX_FOOTER

     每一个标志的含义,请查询MSDN得知,也可以通过宏的单词意义来快速了解,不过以MSDN解释为准。在线MSDN:点此进入在线MSDN点此下载2015版MSDN  点此查看2015版MSDN安装方法    点此下载经典版本MSDN(推荐)

    所以根据单击的位置做处理,如果单击的位置会触发复选框的状态变化,就可以更新复选框的状态,同时可以此时获取更改的状态,同步实时的状态监测。这样就以最小的代价实现了实时状态检测。