CListCtrl是MFC中一个基本的控件,使用率很高,有时候根据需要定制也是很正常的。这里要说的问题就是在定制过程中偶遇的。
通过owner draw的方式定制的CListCtrl,同时还替换了默认的滚动条(实现参见http://www.codeproject.com/Articles/4447/How-to-skin-CListCtrl-including-scrollbars-and-col)。一切都很完美,然而问题随之而来。如下图所示(这里借用了别处现成的图片),最底部的“Item 9”部分可见,当用鼠标选中“Item 9”后,CListCtrl会自动向下滚动,使得“Item 9”完全可见。由于使用了自定义的滚动条,没有接收和处理这个消息,所以当CListCtrl滚动的时候,滚动条没有滚动。
那么自然而然想到的解决办法就是捕获相关消息,然后在响应函数里面更新滚动条的位置。
- 在list control所在的对话框类中添加LVN_ENDSCROLL的消息映射
- 在list control所在的对话框类中添加LVN_ENDSCROLL的处理函数
void CXXXDlg::OnEndScroll(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLVSCROLL pnmLVScroll = (LPNMLVSCROLL) pNMHDR;
m_listCtrl.OnEndScrolling();
*pResult = 0;
}
- 在派生的ClistCtrl的子类中添加滚动条处理函数
void CXXXListCtrl::OnEndScrolling()
{
//add code to update scroll bar position
}
但是在Wince平台上,上述方法行不通!你可能无法接收到LVN_ENDSCROLL消息(也有可能是我的代码有问题),或者你不想让CListCtrl自动滚动。那怎么办呢?偶然发现了一个方法。
- 在派生的ClistCtrl的子类中添加WM_TIMER的消息映射
ON_WM_TIMER()
- 在派生的ClistCtrl的子类中添加WM_TIMER的处理函数,函数体为空,或者添加自己的处理代码,但不要调用基类的函数。
这样就完成了。如果在OnTimer函数体内加断点,会发现即使你没有通过SetTimer启用定时器,OnTimer函数也会被不断调用。所以我猜想,CListCtrl就是通过这种方式来定时检查最底部的行是否完全可见,如果不可见就滚动至完全可见--当然纯属猜想!:)
回头补上一张最终实现的CListCtrl的效果图。