宁静以致远
zgf的blog
<2008年10月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

留言簿(15)

随笔分类

随笔档案

文章档案

友情链接

资料收藏

搜索

最新评论

阅读排行榜

评论排行榜

 
VC知识库BLOG   首页  新随笔  联系  聚合  登录 
  随笔-31 文章-8 评论-99 Trackbacks-0

Virtual List(虚拟列表)是LVS_OWNERDATA 样式的List Ctrl.默认的List Ctrl在插入大量的数据时会变得很慢.在我的破机器上插入不到一万行的数据要几十秒,非常令人不爽.而用Virtual List可以大大加快速度。Virtual List不拥有数据,当需要显示一行时才发消息向父窗口查询显示内容。Virtual List的使用方法与普通List Ctrl稍微有点不同。它有三个重要的消息LVN_GETDISPINFO,LVN_ODCACHEHINT和 LVN_ODFINDITEM。响应这三个消息是关键。

1.创建Virtual List
    只需添加LVS_OWNERDATA风格到List Ctrl就行了。
    m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_OWNERDATA);
2.添加,删除和更改一行
    添加:因为Virtual List不拥有数据,数据存在外部(如:数据库),所以你只需将数据添加到外部,然后m_list.SetItemCount(list_size+1)告诉Virtual List行数加一。这样Virtual List会更改滚动条的样子,以便看上去添加了一行.
    删除:先在外部数据中删除行,然后m_list.SetItemCount(list_size-1)更改滚动条.
    更改:直接修改在外部数据中的行.

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

3.响应LVN_GETDISPINFO消息
    当Virtual List需要显示一行数据时,它发送这个消息给父窗口询问数据内容.父窗口收到消息后从传过来参数中知道Virtual List现在显示的是第几项,第几列,内容是什么类型.然后父窗口在外部数据中找到数据内容,将它返回给Virtual List.
    先添加消息映射,这里用的是反射消息,可以减少控件于父窗口之间的耦合度
    BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
        ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
    END_MESSAGE_MAP()
    相应的响应函数
void CMyListCtrl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult)
{
 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
 LV_ITEM* pItem= &(pDispInfo)->item;
 
 int iItemIndx= pItem->iItem; 
 if (pItem->mask & LVIF_TEXT)
 {
 switch(pItem->iSubItem)
 {
        case 0:
 {
  memcpy(pItem->pszText,(find_index + iItemIndx)->code,8);
  *(pItem->pszText+8) = 0;
 }
        break;
        case 1:
 {
  memcpy(pItem->pszText,(find_index + iItemIndx)-

>description,INDEX_DESLEN);
  *(pItem->pszText+INDEX_DESLEN) = 0;  
 }
 break;
 }
}

 *pResult = 0;
}

4.响应LVN_ODCACHEHINT消息
    这个消息用来缓存请求项的数据.我没用到这个消息,因为我已一次将所有数据读入内存.

5.响应LVN_ODFINDITEM消息
    在资源管理器中浏览文件时,让焦点list上,然后在键盘上输入文件名.资源管理器会自动找到并选中与之最相近的文件.LVN_ODFINDITEM就是实现这个功能的.当焦点在list上时,按键操作会使Virtual List发送LVN_ODFINDITEM给父窗口.父窗口找到相应项并将它选中.
    BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
        ON_NOTIFY_REFLECT(LVN_ODFINDITEM, OnOdfinditemList)
    END_MESSAGE_MAP()

void CMyListCtrl::OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult)
{
 // pNMHDR has information about the item we should find
 // In pResult we should save which item that should be selected
 NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;

 *pResult = -1; // *pResult = -1 表明没有找到

 if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
  return;

 int nlen = _tcslen(pFindInfo->lvfi.psz);

 int startPos = pFindInfo->iStart;
 //Is startPos outside the list (happens if last item is selected)
 if(startPos >= m_list.GetItemCount())
  startPos = 0;

 int currentPos=startPos;

 do
 {
    if(memcmp((find_index + startPos ),pFindInfo->lvfi.psz,nlen) == 0)
    {
  *pResult = currentPos;
  break;  
    }
           currentPos++;
          
    if(currentPos >= m_list.GetItemCount())
  currentPos = 0;
 }while(currentPos != startPos);  
}

     使用Virtual List后的效果令我很满意,但我还是不明白普通list ctrl为什么插入速度这么慢?普通list ctrl的插入操作做了些什么呢?

posted on 2005-11-25 11:47 zgf的blog 阅读(4346) 评论(6)  编辑 收藏
Comments
  • # m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_OWNERDATA);
    周星星
    Posted @ 2007-11-16 11:25
    LVS_OWNERDATA不支持动态切换。
    当OnInitDialog()被调用时,列表视控件已经建立了,这时却想动态切换到LVS_OWNERDATA类型是不被允许的。
  • # re: Virtual List的使用方法
    SosoAyaen
    Posted @ 2008-02-22 11:16
    因为普通的List是把所有的表格数据都添加到控件中去。而VisualList只是把当前屏幕上要显示的数据拷贝到List控件中去。前者的大部分时间主要消耗在了往CListCtrl填充上,而后者的时间主要仅仅消耗在记录表格数据的数据结构中。后者只是往一个链表或者Vector类似的容器中填充你自己的数据结构,这种内存拷贝的速度当然大大快于两者皆顾,甚至是往控件中填充相同的数据。
  • # re: Virtual List的使用方法
    DaHui
    Posted @ 2008-05-23 23:51
    请教如何像一般的ListCtrl那样SetItemData呢? 谢谢。
  • # re: Virtual List的使用方法
    飞凌
    Posted @ 2008-05-27 11:23
    VisualList,不是很喜欢
  • # re: Virtual List的使用方法
    xxx
    Posted @ 2008-08-13 20:04
    请问怎么知道哪些行是正在显示的,读scroll info吗?
  • # re: Virtual List的使用方法
    xxx
    Posted @ 2008-08-13 20:04
    请详细指点一下啊,比如说是report或者icon的方式,我怎么知道哪些行正在显示 
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]