大数据量下的ListCtrl

在windows程序开发中,如果使用了List显示数据,但是目标数据量很大,List性能就会变得很慢,刷新一次需要几秒甚至几十秒的时间,若解决此问题,可使用VirtualList技术 - 即带LVS_OWNERDATA样式的List control。

1、创建

创建时指定LVS_OWNERDATA样式,即在调用CreateWindow或CreateWindowEx时指定。

注:1)不支持动态切换到LVS_OWNERDATA样式,因此通过SetWindowLong等设置该样式将是失败的;

2)本样式不可与LVS_SORTASCENDING或LVS_SORTDESCENDING风格组合,所有的virtual list使用默认的LVS_AUTOARRANGE样式。

2、兼容性问题

1)四种形式的List均支持LVS_OWNERDATA,使用本样式的list不存储条目信息。因此可以应用的有效的状态信息只有LVIS_SELECTED和LVIS_FOCUSED。Virtual list 也不会为每一个条目保持状态和覆盖的图像,然而virtual list可以向父窗口发送一个LVM_SETCALLBACKMASK消息来查询这些图像。

2)受影响消息:

Message

限制描述

LVM_ARRANGE

不支持LVA_SNAPTOGRID样式

LVM_DELETEALLITEMS

设置条目个数为0并清除所有内部选集变量,但是并不是实际地删除所有条目,它将向父窗口发送一个回调的通知消息

LVM_DELETEITEM

仅全选时支持且不实际删除该条目

LVM_GETITEMSTATE

返回焦点和选择状态,即virtual list存储的状态

LVM_GETNEXTITEM

不支持LVNI_CUT,LVNI_HIDDEN,LVNI_DROPHILITED。

LVM_GETWORKAREAS

不支持

LVM_INSERTITEM

仅全选时支持

LVM_SETITEM

不支持

LVM_SETITEMCOUNT

设置当前list的item个数。如果list发送了一个请求所有数据的通知,拥有者必须准备好这些数据

LVM_SETITEMPOSTION

不支持

LVM_SETITEMSTATE

仅支持选择和焦点状态

LVM_SETITEMTEXT

不支持,由拥有者保持

LVM_SETWORKAREAS

不支持

LVM_SORTITEMS

不支持。由拥有者负责以期望的顺序显示item

 

3、添加、删除、更改一行

1)添加:因为Virtual List不拥有数据,数据存在外部(如:数据库),所以你只需将数据添加到外部,然后m_list.SetItemCount(list_size+1)告诉Virtual List行数加一。这样Virtual List会更改滚动条的样子,以便看上去添加了一行。

2)删除:先在外部数据中删除行,然后m_list.SetItemCount(list_size-1)更改滚动条。

3)修改:直接修改在外部数据中的行。

如果这些行是正在显示的行,则需要调用m_list.RedrawItems(nFirst,nLast)。

4、LVN_GETDISPINFO消息

当Virtual List需要显示一行数据时,它发送这个消息给父窗口询问数据内容。父窗口收到消息后从传过来参数中知道Virtual List现在显示的是第几项、第几列,内容是什么类型。然后父窗口在外部数据中找到数据内容,将它返回给Virtual List。

先添加消息映射,这里用的是反射消息,可以减少控件于父窗口之间的耦合度。

BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)

   ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo)

END_MESSAGE_MAP()

 

5、LVN_ODCACHEHINT消息

这个消息用来缓存请求项的数据。

Virtual list 会产生大量的LVN_GETDISPINFO消息,LVN_ODCACHEHINT消息用于帮助提高性能。

该消息指定一个区间,表示该区间内(含边界)的item是最可能需要的,拥有者将该区间内的这些条目加载到缓存中

List经常需要第一条item的信息(index等于0),但是LVN_ODCACHEHINT通知消息不会总是包含item0,但是item0一定要总是在缓存中;

最后一条item也总是被处理,因此拥有者可能需要保持第二个缓存用于包含list最后面的一段。这样LVN_ODCACHEHINT可以对最后一段的缓存请求直接处理,而不需要重新加载。

6、LVN_ODFINDITEM消息

在资源管理器中浏览文件时,让焦点在list上,然后在键盘上输入文件名,资源管理器会自动找到并选中与之最相近的文件。LVN_ODFINDITEM就是实现这个功能的,当焦点在list上时,按键操作会使VirtualList发送LVN_ODFINDITEM给父窗口。父窗口找到相应项并将它选中。

BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)

   ON_NOTIFY_REFLECT(LVN_ODFINDITEM, OnOdFindItem)

END_MESSAGE_MAP()

 

你可能感兴趣的:(MFC,Windows,开发与调式技术)