最近发现用StringGrid读入1000条记录有20个字段只有1-2秒,用listview用9-10秒,读入10000条时相差更大,10-20倍用时,list

  • 主题发起人 主题发起人 apower
  • 开始时间 开始时间
上一期(4)《程序员》有详细的方法呀,看看吧
 
上一期(4)《程序员》有详细的方法呀,看看吧,YES!!!
 
《程序员》在网上能看吗?网址什么?
 
unit HETreeView;
{$R-}
// Pasted from UDDF

// Made by: H?kon Eines
// EMail: haakon.eines@finale.no
// Date: 21.01.1997
// Description: A Speedy TreeView?
(*
TTREEVIEW:
128 sec. to load 1000 items (no sorting)*
270 sec. to save 1000 items (4.5 minutes!!!)

THETREEVIEW:
1.5 sec. to load 1000 items - about 850% faster!!! (2.3 seconds with sorting = stText)*
0.7 sec. to save 1000 items - about 3850% faster!!!

NOTES:
- All timings performed on a slow 486SX 33 MhZ, 20 Mb RAM.

- * If the treeview is empty, loading takes 1.5 seconds,
else add 1.5 seconds to clear 1000 items (a total loading time of 3 seconds).
This is also the case for the TTreeView component (a total of 129.5 seconds).
The process of clearing the items, is a call to
SendMessage(hwnd, TVM_DELETEITEM, 0, Longint(TVI_ROOT)).
*)

interface

uses
SysUtils, Windows, Messages, Classes, Graphics,
Controls, Forms, Dialogs, ComCtrls, CommCtrl;

type
THETreeView = class(TTreeView)
private
FSortType: TSortType;
procedure SetSortType(Value: TSortType);
protected
function GetItemText(ANode: TTreeNode): string;
public
constructor Create(AOwner: TComponent); override;
function AlphaSort: Boolean;
function CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
procedure LoadFromFile(const AFileName: string);
procedure SaveToFile(const AFileName: string);
procedure GetItemList(AList: TStrings);
procedure SetItemList(AList: TStrings);
//'Bold' should have been a property of TTreeNode, but...
function IsItemBold(ANode: TTreeNode): Boolean;
procedure SetItemBold(ANode: TTreeNode; Value: Boolean);
published
property SortType: TSortType read FSortType write SetSortType default stNone;
end;

procedure Register;

implementation

function DefaultTreeViewSort(Node1, Node2: TTreeNode; lParam: Integer): Integer; stdcall;
begin
{with Node1 do
if Assigned(TreeView.OnCompare) then
TreeView.OnCompare(Node1.TreeView, Node1, Node2, lParam, Result)
else}
Result := lstrcmp(PChar(Node1.Text), PChar(Node2.Text));
end;

constructor THETreeView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FSortType := stNone;
end;

procedure THETreeView.SetItemBold(ANode: TTreeNode; Value: Boolean);
var
Item: TTVItem;
Template: Integer;
begin
if ANode = nil then Exit;

if Value then Template := -1
else Template := 0;
with Item do
begin
mask := TVIF_STATE;
hItem := ANode.ItemId;
stateMask := TVIS_BOLD;
state := stateMask and Template;
end;
TreeView_SetItem(Handle, Item);
end;

function THETreeView.IsItemBold(ANode: TTreeNode): Boolean;
var
Item: TTVItem;
begin
Result := False;
if ANode = nil then Exit;

with Item do
begin
mask := TVIF_STATE;
hItem := ANode.ItemId;
if TreeView_GetItem(Handle, Item) then
Result := (state and TVIS_BOLD) <> 0;
end;
end;

procedure THETreeView.SetSortType(Value: TSortType);
begin
if SortType <> Value then
begin
FSortType := Value;
if ((SortType in [stData, stBoth]) and Assigned(OnCompare)) or
(SortType in [stText, stBoth]) then
AlphaSort;
end;
end;

procedure THETreeView.LoadFromFile(const AFileName: string);
var
AList: TStringList;
begin
AList := TStringList.Create;
Items.BeginUpdate;
try
AList.LoadFromFile(AFileName);
SetItemList(AList);
finally
Items.EndUpdate;
AList.Free;
end;
end;

procedure THETreeView.SaveToFile(const AFileName: string);
var
AList: TStringList;
begin
AList := TStringList.Create;
try
GetItemList(AList);
AList.SaveToFile(AFileName);
finally
AList.Free;
end;
end;

procedure THETreeView.SetItemList(AList: TStrings);
var
ALevel, AOldLevel, i, Cnt: Integer;
S: string;
ANewStr: string;
AParentNode: TTreeNode;
TmpSort: TSortType;

function GetBufStart(Buffer: PChar; var ALevel: Integer): PChar;
begin
ALevel := 0;
while Buffer^ in [' ', #9] do
begin
Inc(Buffer);
Inc(ALevel);
end;
Result := Buffer;
end;

begin
//Delete all items - could have used Items.Clear (almost as fast)
SendMessage(handle, TVM_DELETEITEM, 0, Longint(TVI_ROOT));
AOldLevel := 0;
AParentNode := nil;

//Switch sorting off
TmpSort := SortType;
SortType := stNone;
try
for Cnt := 0 to AList.Count-1 do
begin
S := AList[Cnt];
if (Length(S) = 1) and (S[1] = Chr($1A)) then Break;

ANewStr := GetBufStart(PChar(S), ALevel);
if (ALevel > AOldLevel) or (AParentNode = nil) then
begin
if ALevel - AOldLevel > 1 then raise Exception.Create('Invalid TreeNode Level');
end
else begin
for i := AOldLevel downto ALevel do
begin
AParentNode := AParentNode.Parent;
if (AParentNode = nil) and (i - ALevel > 0) then
raise Exception.Create('Invalid TreeNode Level');
end;
end;
AParentNode := Items.AddChild(AParentNode, ANewStr);
AOldLevel := ALevel;
end;
finally
//Switch sorting back to whatever it was...
SortType := TmpSort;
end;
end;

procedure THETreeView.GetItemList(AList: TStrings);
var
i, Cnt: integer;
ANode: TTreeNode;
begin
AList.Clear;
Cnt := Items.Count -1;
ANode := Items.GetFirstNode;
for i := 0 to Cnt do
begin
AList.Add(GetItemText(ANode));
ANode := ANode.GetNext;
end;
end;

function THETreeView.GetItemText(ANode: TTreeNode): string;
begin
Result := StringOfChar(' ', ANode.Level) + ANode.Text;
end;

function THETreeView.AlphaSort: Boolean;
var
I: Integer;
begin
if HandleAllocated then
begin
Result := CustomSort(nil, 0);
end
else Result := False;
end;

function THETreeView.CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
var
SortCB: TTVSortCB;
I: Integer;
Node: TTreeNode;
begin
Result := False;
if HandleAllocated then
begin
with SortCB do
begin
if not Assigned(SortProc) then lpfnCompare := @DefaultTreeViewSort
else lpfnCompare := SortProc;
hParent := TVI_ROOT;
lParam := Data;
Result := TreeView_SortChildrenCB(Handle, SortCB, 0);
end;

if Items.Count > 0 then
begin
Node := Items.GetFirstNode;
while Node <> nil do
begin
if Node.HasChildren then Node.CustomSort(SortProc, Data);
Node := Node.GetNext;
end;
end;
end;
end;

//Component Registration
procedure Register;
begin
RegisterComponents('Win32', [THETreeView]);
end;


end.
 
ListView不能修改数据(第一列能吧),再说没必要一下显示那么多啊。

楼上的是TreeView吧
 
ListView中怎样对各个字段排序啊?不是重新添加节点时排!
 
用VirtualTreeView,速度极快,又没有Virtual-ListView的限制。
功能丰富。排序、Custom-Draw应有尽有。有了这个,我已经不用ListView了。
我认为它是目前最好的ListView,应该加到下一版本的Delphi中去
(作者的另一组件"Windows XP Theme Manager"已经被Borland包括到Delphi7里了)。
它实际上是个Tree/ListView,就象OutLook里的那样。
网址:http://www.lischke-online.de/。

模糊查找只有用遍历,或用DataSet的功能,没别的方法。但如果用DataSet,一般就用DBGrid了。
精确查找,可用各种Map,如Hash,各种B树的变体等。我经常用来建立索引。

我的一个最近程序,20000多条记录,从文件读入到显示,
并且建立所有记录的2个索引,不到2秒(CII533,256M),要是P4就更快了。
 
我使用TStringList保存数据,ListView显示,ListView.OwnerData:=True;
5列,30万行(30万条记录)使用zlib压缩保存,仅1.74秒,时间花费在读入文件、解压缩中。
 
楼上的说的好

存数据要用快的方法 最好是调在内存来读
要不直接读HD

压缩的话看实际情况

用户只看一部分
把需要的读出到你认为友好的界面就够了
 
请问高手skadon,有些具体的例子吗?贴出来吧.
 
Virtual Listview,与listview界面一样,速度飞快。,Delphi中自带例子
 
EMList: TListView;

var
Ems :TStrings; //存放数据,一行一个记录,每行5列,用逗号隔开
procedure TForm1.FormCreate(Sender: TObject);
begin
Ems:=TStringList.Create;
Ems.LoadFromFile('a.txt');
end;

procedure TForm1.EMListData(Sender: TObject; Item: TListItem);
var
st:string;
j,i:integer;
begin
if EMList.Tag=0 then exit; //不需要显示时退出
try
st:=Ems[Item.Index];
j:=Pos(',',st);
try i:=strtoint(Sta[Item.Index]) except i:=0; end;
Item.ImageIndex :=i;
Item.SubItems.Add(inttostr(Item.Index+1));
Item.SubItems.Add(Copy(st,1,j-1));
delete(st,1,j); j:=Pos(',',st);
Item.SubItems.Add(Copy(st,1,j-1));
delete(st,1,j);
Item.SubItems.Add(st + '');
Item.SubItems.Add(WorkStatus);
except end;
end;
 
在装载100条后,设置“重画”属性为假,完了后再真。
 
别人的笔记,你看看???
标题?: 让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秒。
至此,问题得到解决。相信许多正在苦苦寻觅第三方控件的朋友能够由此得到一些启发
 
不用再找其他什么了。
在Delphi/BCB下,对于ListView、TreeView,最好的也是唯一的选择就是免费控件:VirtualListView。
只要用过就知道我为什么这么说。
http://www.delphi-gems.com/VirtualTreeview/VT.php
在其身上还衍生出了VirtualExplorerTree/List,VirtualDBList。
添加百万条记录也不过1秒。
 

Similar threads

D
回复
0
查看
2K
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部