下面的程序的目的是把一个记录集的数据添加到一个TListView控件中特别说明:
geoRecordset是一个GRecordset对象,有别于Delphi的TRecordset类,故不能用传统的TDataSet和TDBGrid等类来进行绑定。
跟踪代码发现这行代码执行lstListItem.Caption := geoRecordset.GFields.Item[strArrFields[0]].Value较费时。测试说明:
现在我测试了一下,向其中添加1000条数据需要约1分钟,机器配置为:赛扬1G、512兆和10兆网卡(系统是CS结构)。我对算法以及其优化不是很有研究,特来请高人指点,谢谢!!!
type
  PStateData = ^TStateData;
  TStateData = record
    strArrFields: array of string;
  end;{-----------------------------------------------------------------------------
  方法: g_pro_GetFieldEnNameOnTable
  作者: 黄仁光
  日期: 2004年10月27日
  参数: geoRecordset: OleVariant; strTableName: string; var objStateData: PStateData
  结果: None
  备注: 获取给定表的字段(除去了BLOB字段和空间字段)
-----------------------------------------------------------------------------}procedure g_pro_GetFieldEnNameOnTable(
  geoRecordset: OleVariant; strTableName: string; var objStateData: PStateData);
var
  iLoop: Integer;
  objGField: OleVariant;
  iType: Integer;
  iLength: Integer;
begin
  for iLoop := 0 to geoRecordset.GFields.Count - 1 do
  begin
    objGField := geoRecordset.GFields[iLoop];
    iType := objGField.Type; {11,12,8}
    if (iType <> 32) and (iType <> 15) and (iType <> 33) then
    begin
      if Trim(objGField.Name) <> '' then
      begin
        iLength := Length(objStateData^.strArrFields);
        SetLength(objStateData^.strArrFields, iLength + 1);
        objStateData^.strArrFields[iLength] := objGField.Name;
      end;
    end;
  end;
end;{-----------------------------------------------------------------------------
  方法: g_pro_AddOneColumnCaptionToListView
  作者: 黄仁光
  日期: 2004年10月27日
  参数: strFieldName: string; lsvListView: TListView
  结果: None
  备注: 向TListView中添加一列 
-----------------------------------------------------------------------------}procedure g_pro_AddOneColumnCaptionToListView(
strFieldName: string; lsvListView:TListView);
var
  strChFieldName: string;
  lscNewColumn: TListColumn;
begin
  lscNewColumn := lsvListView.Columns.Add;
  lscNewColumn.Width := ColumnHeaderWidth;
  lscNewColumn.Caption := strFieldName;
end;{-----------------------------------------------------------------------------
  方法: g_pro_AddOneRecordValueToListView
  作者: 黄仁光
  日期: 2004年10月27日
  参数: geoRecordset: OleVariant; strArrFields: array of string; lsvListView: TListView
  结果: None
  备注: 向TListView中添加添加一行 
-----------------------------------------------------------------------------}procedure g_pro_AddOneRecordValueToListView(
  geoRecordset: OleVariant; strArrFields: array of string; lsvListView: TListView);
var
  lstListItem: TListItem;
  iLoop: Integer;
begin
  if Length(strArrFields) > 0 then
  begin
    lstListItem := lsvListView.Items.Add;
    if not VarIsNull(geoRecordset.GFields.Item[strArrFields[0]].Value) then
    begin
      lstListItem.Caption := geoRecordset.GFields.Item[strArrFields[0]].Value;
    end
    else
    begin
      lstListItem.Caption := '';
    end;    for iLoop := 1 to Length(strArrFields) - 1 do
    begin
      if not VarIsNull(geoRecordset.GFields.Item[strArrFields[iLoop]].Value) then
      begin
        lstListItem.SubItems.Add(geoRecordset.GFields.Item[strArrFields[iLoop]].Value);
      end
      else
      begin
        lstListItem.SubItems.Add('');
      end;
    end;
  end;
end;{-----------------------------------------------------------------------------
  方法: g_pro_AddDataToListView
  作者: 黄仁光
  日期: 2004年10月27日
  参数: geoRecordset: OleVariant; strTableName: string; lsvListView: TListView
  结果: None
  备注: 将地理实体表所对应的数据添加到TListView中,去除了BLOB字段和空间字段 
-----------------------------------------------------------------------------}procedure g_pro_AddDataToListView(
  geoRecordset: OleVariant; strTableName: string; lsvListView: TListView);
var
  objStateData: PStateData;
  iLoop: Integer;
begin
  try
    lsvListView.Columns.Clear;
    lsvListView.Items.Clear;
    New(objStateData);
    SetLength(objStateData^.strArrFields, 0);
    g_pro_GetFieldEnNameOnTable(geoRecordset, strTableName, objStateData);
    for iLoop := 0 to Length(objStateData^.strArrFields) - 1 do
    begin
      g_pro_AddOneColumnCaptionToListView(objStateData^.strArrFields[0], lsvListView);
    end;    //有了这两条语句,就能保证得到正确的记录数量
    geoRecordset.MoveLast;
    geoRecordset.MoveFirst;
    for iLoop := 0 to geoRecordset.RecordCount - 1 do
    begin
      g_pro_AddOneRecordValueToListView(geoRecordset, objStateData^.strArrFields, lsvListView);
      geoRecordset.MoveNext;
    end;
  except  end;
end;

解决方案 »

  1.   

    你不如重新写一个程序,不用他这个
    比如
    ADOQuery1.sql.text:='select * from myatable' ;
    ADOQuery1.open;
    while not ADOQuery1.eof do
    begin
      Item:=ListView1.items.Add;
      Item.caption:=ADOQurery.fieldvalues['field1'];
      Item.subitem.add(ADOQuery1.fieldvalues['field2']);
      ADOQuery1.next;
    end;
      

  2.   

    其实就是g_pro_AddOneRecordValueToListView方法的问题,其实我写的方法应当说很清晰明了,我解释一下吧:
    (1)g_pro_GetFieldEnNameOnTable:传入一个表的名称,将需要的字段放在下面的结构中
    type
      PStateData = ^TStateData;
      TStateData = record
        strArrFields: array of string;
      end;(2)g_pro_AddOneColumnCaptionToListView:将上面得到的字段一个一个的添加到TListView中,就是加上一个一个的标题头(TListColumn);(3)g_pro_AddOneRecordValueToListView:这个方法是这儿最主要的方法,也就是请大家主要帮我分析的方法,该方法是把一条记录的数据添加到TListView中;(4)g_pro_AddDataToListView:传入一个记录集、对应的表名称以及要填充数据的TListView对象,它掉用上面的三个方法完成数据的填充。
      

  3.   

    OleVariant这种类型能够确定的最好不用
    数据量大的时候特别影响速度
      

  4.   

    1、你这种方法不对,不应该一次读入所有数据,只读入当前显示的,翻屏时再读,就象dataset那样处理,不然你以后假如数据上万,那再怎么优化都没用
    2、你可以用自定义dataset的方法,从customdataset中引出(记不太清楚,很久没用了),在那些方法中读自己的数据,这样就可以和标准的dataset一样被dbgrid认识,也能被其他的db控件认识,我以前做股票时用过这方法,能将那些股票系统的专用数据库当标准dataset使用
      

  5.   

    TListItems.BeginUpdate
    ......
    TListItems.EndUpdate
      

  6.   

    stonewind() 的第一种方法我想过,就是不知道怎么做。
      

  7.   

    第一种方法中,你需要定义TListView的一些事件,在其中输入数据 
    比如:OnData,就是在显示以前调用的事件,如果你定义了自己的过程,比如DataProc并赋给OnData,那显示以前就要运行DataProc,DataProc结构为:type DataProc = procedure(Sender: TObject; Item: TListItem) of object;,这里,Sender就是TListView,Item就是要显示的项,你就可以修改将要显示的数据,不就可以实现只在要显示时读入数据了吗产只是其中一个事件,如你多了解些其中的事件和调用关系,相信可以作得更好。
    第一种方法的麻烦在于,对于将要用到的每一个控件,都要自己定义,如你只用这一个,倒没什么,不然,还是定义Dataset好
      

  8.   

    谢谢 stonewind() ,你提供的方法我正在考虑怎么做,希望有更多的同道参与。
      

  9.   

    存储过程以及游标等方法是肯定用不上的。
    (系统使用的是Oracle数据库)。
      

  10.   

    数据多时ListView很慢,哪怕你不从数据库中取数据。
    建议使用ListView的Virtual模式,可以看看delphi的例子Virtual Listview
      

  11.   

    用Sql server的话,Ado数据集的游标位置很影响查询速度,不知你用的那个控件有没有游标位置的设定,有的话设为服务端游标试试。
    还有前面的兄弟说的,动态数组和ole变量都是效率很低的数据类型,从我以前测试结果看,速度相差非常之大,建议还是不要用的好
      

  12.   

    关注,LISTVIEW结合数据库可做酒店系统的房态盘和餐态盘,并且在别的应用系统中都可用到,苦找数年,也没有找到一合适的控件来做此功能!!!!!!!!!!!!!!!!!!!!!
    关注!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      

  13.   

    现在我用的新方法就是huangzb(黄龙)说的分页,即分多次加载方式。