一、http://topic.csdn.net/t/20020728/13/905888.html
ListView在操作大量数据时慢的问题! (CSDN-CSDN社区-C++ Builder-基础类) :
--> 26楼 max_wzg (暴走-银狼) :
采用常规方法处理ListView,在数据量大时无论是还是用了BeginUpdata和EndUpdata()还是处理WM_EraseBkgnd信息都不会得到理想的效果,那答案是什么呢?
嗯,采用所谓Virtual ListView。
说起来很神秘,其实点通了很简单。
在于把ListView-> OwnerData设为true,然后直接设置
ListView-> Items-> Count为数据总数,实际的数据可以保在任意其它速度较快且可直接索引的容器里(如STL中的vector),然后关键是在OnData事件中写入代码通过Item-> Index从容器中(如vector)取出数据,然后用
Item-> Caption = ???;
Item-> SubItems-> Add(???);
Item-> SubItems-> Add(???);
来动态的写入数据到ListView用于UI显示,如此Virtual ListView即完成.
一个完整的简单例子如下:/*Unit1.h*/ //--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include #include #include #include #include #include using namespace std; //--------------------------------------------------------------------------- struct ListViewData { AnsiString Caption; AnsiString SubItems1; AnsiString SubItems2; AnsiString SubItems3; }; class TForm1 : public TForm { __published: // IDE-managed Components TListView *ListView1; void __fastcall ListView1Data(TObject *Sender, TListItem *Item); private: // User declarations vector m_lvDataVector; public: // User declarations __fastcall TForm1(TComponent* Owner); __fastcall ~TForm1(); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif /*unit1.cpp*/ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h " //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm " TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { ListView1-> OwnerData = true; const int iListViewCount = 5000; ListView1-> Items-> Count = iListViewCount; for(int i = 0; i < iListViewCount; ++i) { ListViewData *plvData = new ListViewData; plvData-> Caption = "Caption " + AnsiString(i); plvData-> SubItems1 = "SubItems1 " + AnsiString(i); plvData-> SubItems2 = "SubItems2 " + AnsiString(i); plvData-> SubItems3 = "SubItems3 " + AnsiString(i); m_lvDataVector.push_back(plvData); } } __fastcall TForm1::~TForm1() { int iCount = ListView1-> Items-> Count; for(int i = 0; i < iCount; ++i) { ListViewData *plvData = m_lvDataVector[i]; delete plvData; } } //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item) { ListViewData *plvData = m_lvDataVector[Item-> Index]; Item-> Caption = plvData-> Caption; Item-> SubItems-> Add(plvData-> SubItems1); Item-> SubItems-> Add(plvData-> SubItems2); Item-> SubItems-> Add(plvData-> SubItems3); } //---------------------------------------------------------------------------
--> 28楼 cdws222 (二当家) :
不过如果你看到这个回复候能不能解释一下
vector m_lvDataVector;是什么意思
我是个菜鸟,还不会这个
--> 29楼 max_wzg (暴走-银狼) :
vector是标准C++库的一部分,STL中的容器类之一,
你可以简单地把它理解为C++内置数组的增强版,详细的你可以看看有关标准C++的书或文章,可以把这当成开始学习泛形编程的一个好的开端,推荐《C++Primer》。
学好标准C++库非常重要,既然用BCB,就要充分发挥C++的强大功能,不然真的还不如去用Delphi.
二、http://topic.csdn.net/t/20020728/13/905888.html
讨论ListView里显示十万级以上记录时,象SQL Server里的返回所有行的方式显示记录,怎么实现? (CSDN-CSDN社区-C++ Builder-基础类) :
--> 25楼 bigwhiteshark (变性鲨鱼) :
哈哈正中本人下怀
如何用TListView来处理大量数据
采用常规方法处理ListView,在数据量大时无论是还是用了BeginUpdata和EndUpdata()
还是处理WM_EraseBkgnd信息都不会得到理想的效果,那答案是什么呢?嗯,
采用所谓Virtual ListView技术。说起来很神秘,其实点通了很简单。
通常ListView中的所有数据都是由ListView自己来管理的,它负责这些数据空间的分配和释放,
当你把ListView-> OwnerData设为true时,ListView就把数据的管理权交给了你,而它只负责显示。
这时你需要自己来为数据分配和释放空间,至于你怎样来管理这些数据完全有你自己来定,
ListView完全不关心,当ListView需要显示某条数据时,它就调用OnData事件,
你只要在这个事件的处理函数里指定ListView即将显示的Item的内容就可以了。
这就是所谓的Virtual ListView技术。
由于ListView对数据管理的功能强大,随之而来的却是效率低下,
如果你采用更高效的数据管理方式就会极大的改变效率。
而且Virtual ListView只在数据需要显示时才调用OnData事件载入数据,所以速度很快。
下面的例子中,假设ListView中需要显示4列数据,所有的数据被保存在vector里。
/*Unit1.h*/ //--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include #include #include #include #include #include using namespace std; //--------------------------------------------------------------------------- struct ListViewData //用于存储一条数据的结构体 { AnsiString Caption; AnsiString SubItems1; AnsiString SubItems2; AnsiString SubItems3; }; class TForm1 : public TForm { __published: // IDE-managed Components TListView *ListView1; void __fastcall ListView1Data(TObject *Sender, TListItem *Item); private: // User declarations vector m_lvDataVector; //用于存储所以数据的向量 public: // User declarations __fastcall TForm1(TComponent* Owner); __fastcall ~TForm1(); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif /*unit1.cpp*/ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h " //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm " TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { ListView1-> OwnerData = true; const int iListViewCount = 5000; ListView1-> Items-> Count = iListViewCount; //必须指定,以使ListView知道其虚拟数据量 //保存数据 for(int i = 0; i < iListViewCount; ++i) { ListViewData *plvData = new ListViewData; plvData-> Caption = "Caption " + AnsiString(i); plvData-> SubItems1 = "SubItems1 " + AnsiString(i); plvData-> SubItems2 = "SubItems2 " + AnsiString(i); plvData-> SubItems3 = "SubItems3 " + AnsiString(i); m_lvDataVector.push_back(plvData); //向vector中添加一项 } } __fastcall TForm1::~TForm1() { int iCount = ListView1-> Items-> Count; for(int i = 0; i < iCount; ++i) { ListViewData *plvData = m_lvDataVector[i]; delete plvData; //释放数据占用的资源 } m_lvDataVector.clear(); //清空vector中所有条目 } //--------------------------------------------------------------------------- //ListView在要显示某条数据时会调用这个函数 void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item) { if(Item-> Index > m_lvDataVector.size()) return; ListViewData *plvData = m_lvDataVector[Item-> Index]; //指定要显示的条目的数据 Item-> Caption = plvData-> Caption; Item-> SubItems-> Add(plvData-> SubItems1); Item-> SubItems-> Add(plvData-> SubItems2); Item-> SubItems-> Add(plvData-> SubItems3); }
速度很快,5000条数据只要1秒左右.
在使用Virtual ListView方式时,如果要对数据排序,只需对你保存的内部数据(这里时vector对象)排序,然后ListView-> Refresh()即可。这时你在ListView中看到的数据就是排好序的数据了。
2002-12-12 大白鲨
三、http://topic.csdn.net/t/20040719/17/3189489.html
300分求解决listview大量数据添加慢的方法 (CSDN-CSDN社区-Delphi-VCL组件开发及应用 ):
--> 3楼 fei19790920 (饭桶超人II) :
标题: 让ListView更快的显示数据
关键字: Listview,Virtual,海量数据
分类: 成功心得
密级: 公开
(评分: , 回复: 6, 阅读: 312) ??
最近刚刚完成一个项目,用Listview取代难看的DBGrid显示数据。在我的机器上运行正常。一切看起来还不错,但是,且慢。在用户那里用实际数据一显示,我当场晕倒。天哪,区区4000条记录,居然显示了2分钟32秒……
经过试验,发现Listview在插入1000条记录时速度尚可忍受,然后插入速度逐渐变慢。随着记录数的增加,速度越来越慢。
怎么办?使用第三方控件?
正在彷徨无计之际,CSDN和大富翁上的相关帖子让我受到启发。对,就用Virtual模式。
首先研究大家提到的一个Delphi自带的例子,就是{$DELPHI}/Demos/Virtual Listview文件夹下的那个工程。
让Listview进入Virtual模式其实很简单。设置Listview的OwnerData属性为True,然后设置Listview.Items.Count的值,最后在Listview的OnData事件处理方法中给指定Index的Item提供Caption、SubItems等信息即可。
当然,你需要自己管理你要显示的数据。我使用了一个TList类,当然也可以使用数组。
以上是我在自己重新编写的Demo中观察到的。但是,当我依照此思路将其运用到我的项目中时,发现当鼠标在屏幕上移动的时候,Listview本身不停的闪烁,根本无法工作。这是怎么回事?
我在网上寻寻觅觅,但迟迟找不到答案。也动过在大富翁和CSDN上询问的念头,但是又不甘心。
察看TListView的源码,除了看到OnData实际上由系统LVN_GETITEMINFO消息触发外,没有任何可用信息。
仔细对比我写的Demo、Delphi自带的例程和我的项目代码,发现一点重大的不同。那就是,前两者在Ondata事件处理方法中Item.SubItems是用Add方法添加的,而我的项目中是直接给Item.SubItems.CommaText赋值。难道是因为这一点?我作了一些修改,呵呵,大功告成!
经过实测,现在显示4000条复杂纪录只需区区30秒,而这时间主要是花费在数据库(我们的表结构确实存在问题)查询上,相信如果数据库结构得以优化,显示4000条记录需时绝不会超过10秒。
至此,问题得到解决。相信许多正在苦苦寻觅第三方控件的朋友能够由此得到一些启发
--> 4楼 fei19790920 (饭桶超人II) :
{用ListView处理显示百万以上的数据,如果用传统的方法,即使使用BeginUpdate,EndUpdate,速度也远远不能满足要求,这个时候就要使用ListView的OwnerData功能了!OwnerData允许使用一个Vitual ListView和内存中的数据对应,我们只要在OnData中返回数据即可。 OnData有一个参数Item,其中Item.Index就是第N项需要显示的数据! 另外还可以利用OnDataHint,当数据发生变化的时候,进行的处理。具体的请参考Delphi的Demo VirtualListView。注意,一定要设置ListView.Items.Count属性,否则不会显示数据。 } //上面是猛料的 / 事例: 1。 listview的ownerdata为true; 2。 procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem); begin item.caption:= '0 '; item.SubItems.Add( '1 '); item.SubItems.Add( '2 '); item.SubItems.Add( '3 '); end; 3。 procedure TForm1.FormCreate(Sender: TObject); begin ListView1.Columns.Clear; ListView1.Columns.Add.Caption := 'A '; ListView1.Columns.Add.Caption := 'B '; ListView1.Columns.Add.Caption := 'C '; ListView1.Columns.Add.Caption := 'D '; ListView1.items.count:=10;//控制总数 end; /你可以举一反三