在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
众所周知,Delphi ListView类直接进行Add、Update、Delete操作的速度是比较慢的,尤其是当数据量较大时,比如数据量达到5000、10000、50000时,速度真是可以说是“慢得惊人”。其实快速操作的方法非常简单,就当大家都知道了。在本人的工作中,很多项目都用到ListView,并且对速度的响应要求比较高,于是发生了快速操作ListView的代码散布于多个项目大量模块中的问题,并且,当界面层数据显示要求发生改变时,自然发生“重复性代码的通用问题”。考虑到对以前版本的兼容性问题,也一直没有引用第三方的成熟组件。鉴于:“程序中的重复代码最易引发问题,必须消除”的实践经验,自己设计了一个比较通用的解决此类问题的类结构。当然,远不是什么“通用框架”了(眼下市面上很多人喜欢把自己做的无论什么东西通称为框架)。在采用此结构的项目中,很容易实现MVC模式,达到业务逻辑与界面显示分离的低级的、基础的要求。 Delphi ListView快速操作通用实现 作者:成晓旭 众所周知,Delphi ListView类直接进行Add、Update、Delete操作的速度是比较慢的,尤其是当数据量较大时,比如数据量达到5000、10000、50000时,速度真是可以说是“慢得惊人”。其实快速操作的方法非常简单,就当大家都知道了。在本人的工作中,很多项目都用到ListView,并且对速度的响应要求比较高,于是发生了快速操作ListView的代码散布于多个项目大量模块中的问题,并且,当界面层数据显示要求发生改变时,自然发生“重复性代码的通用问题”。考虑到对以前版本的兼容性问题,也一直没有引用第三方的成熟组件。鉴于:“程序中的重复代码最易引发问题,必须消除”的实践经验,自己设计了一个比较通用的解决此类问题的类结构。当然,远不是什么“通用框架”了(眼下市面上很多人喜欢把自己做的无论什么东西通称为框架)。在采用此结构的项目中,很容易实现MVC模式,达到业务逻辑与界面显示分离的低级的、基础的要求。 (因为,目前CSDN的软件上传功能不可用,我只有将部分代码片断放在文档中,有需要完整源码者,请留言) 类层次结构: ListView基础操作封装在LVControler包中,核心的类是TCXXLVControler: (说明:LVControler类是被封装通用类结构内,外部用户是不需要了解和访问的,所以不作介绍。) 传统的ListView操作基类是TLVCommonClass,如果想用传统的方法增、删、改ListView中的数据,可以直接从此类继承。 源码如下:
具体的一个从此类继承下来的用于Socket界面显示的TLVSocket的类Overvivw如下: 源码如下:
快速的ListView操作基类是TLVQuickClass,如果想用快速方法增、删、改ListView中的数据,可以直接从此类继承。 主要方法:(可以看到,里面没有真正的Public方法,子类也仅需实现两个Protected的virtual方法) 源码如下:
此类中,要求每个具体应用的子类必须实现的方法仅有两个:CheckFound():根据具体应用检测的数据是否已经存在;ProcOnDataDetail():客户端ListView的On 具体的一个从此类继承下来的用于Socket界面显示的TLVQuickSocket的类Overvivw如下: 可以看出:子类实现了两个抽象的虚方法,其它的方法,都是根据业务需要,类用户自行增加的。 源码如下:
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi co // 模块名称: Delphi之ListView显示控制类---应用层:Soft socket类定义单元 // 模块描述: // 单元文件: unLVSoftSocket.pas-->unLVQuickSocket.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2005-09-26 // // 修改历史: 2006-06-16 // 修改描述: 增加通过TList来高速增加、更新、删除数据 // 先用吧,以后再优化和完善 // 修改历史: 2006-07-10 // 修改描述: 成功地将ListView的On // 修改历史: 2006-07-11 // 修改描述: 重大重构:将此类分成两个类:TLVSoftSocket-->TLVSoftSocket和TLVQuickSocket // 以遵循SRP原则 //------------------------------------------------------------------------------ unit unLVQuickSocket; interface uses ComCtrls,Classes,SysUtils,Windows, unLVQuickClass,unLVDefine; type TLVQuickSocket = class(TLVQuickClass) private protected class function CheckFound(const pData:Pointer;const aKey:variant):boolean;override; class procedure ProcOnDataDetail(const pData:Pointer;var Item: TListItem);override; public constructor Create(); destructor Destroy();override; procedure InitListView(var lvTemp:TListView); //快速方法 //暂时这样增加,以后在重构到基类中 procedure AddToLVSocketQuick(const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); procedure UpdateLVSocketQuick(const aUniqueID:integer;const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); procedure DeleteLVSocketQuick(const aUniqueID:integer;const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); procedure DeleteAllLVSocket(var lvTemp:TListView); procedure On function GetDataCount():integer; end; implementation ...{ TLVQuickSocket } procedure TLVQuickSocket.AddToLVSocketQuick( const aSocketStatus: TSocketStatusInfo;var lvTemp:TListView); begin AddItemDataToListView(@aSocketStatus,sizeof(aSocketStatus),lvTemp); end; class function TLVQuickSocket.CheckFound(const pData: Pointer; const aKey: variant): boolean; var p:^TSocketStatusInfo; begin p := pData; Result := (p.UniqueID = aKey); end; constructor TLVQuickSocket.Create; begin inherited Create(); end; procedure TLVQuickSocket.DeleteAllLVSocket(var lvTemp: TListView); begin DeleteAllListView(lvTemp); end; procedure TLVQuickSocket.DeleteLVSocketQuick(const aUniqueID:integer; const aSocketStatus: TSocketStatusInfo;var lvTemp:TListView); begin DeleteItemDataToListView(aUniqueID,@aSocketStatus,sizeof(aSocketStatus),lvTemp); end; destructor TLVQuickSocket.Destroy; begin inherited Destroy; end; function TLVQuickSocket.GetDataCount(): integer; begin Result := Self.GetLVListCount(); end; procedure TLVQuickSocket.InitListView(var lvTemp: TListView); begin InitListViewColumns(SocketStrBuffer,SocketWidthBuffer,lvTemp); end; procedure TLVQuickSocket.On begin Self.On end; class procedure TLVQuickSocket.ProcOnDataDetail(const pData: Pointer;var Item: TListItem); var pSocket:^TSocketStatusInfo; begin //这两个有什么不同? //CopyMemory(pSocket,pData,sizeof(TSocketStatusInfo)); pSocket := pData; Item.Caption := IntToStr(pSocket.GroupID); Item.SubItems.Add(IntToStr(pSocket.UniqueID)); Item.SubItems.Add(pSocket.IPAddress); Item.SubItems.Add(pSocket.SubItemName); Item.SubItems.Add(pSocket.LoginTime); Item.SubItems.Add(pSocket.SendNumber); Item.SubItems.Add(pSocket.RecNumber); Item.SubItems.Add(pSocket.Remark); end; procedure TLVQuickSocket.UpdateLVSocketQuick(const aUniqueID:integer; const aSocketStatus: TSocketStatusInfo;var lvTemp:TListView); begin UpdateItemDataToListView(aUniqueID,@aSocketStatus,sizeof(aSocketStatus),lvTemp); end; end.
小结: 应用此类结构实现ListView快速数据操作的优势: <!--[if !supportLists]-->1、 <!--[endif]-->可以快速实现MVC模式,达到界面显示与业务逻辑的分离。在Controllor类中,实例化数据显示子类,调用相应方法即可实现显示数据的增、删、改。 <!--[if !supportLists]-->2、 <!--[endif]-->与原始的快速方法相比,封装了内存数据List,大大简化了List对象的操作(尤其是当有很多相同或者类似数据要求在不同Form的ListView中显示时),并减少了List的创建、数据操作、释放等操作时发生错误的可能性。 <!--[if !supportLists]-->3、 <!--[endif]-->简化了多个相同、类似数据显示的控制代码,针对每个份要显示的数据及ListView,只需要实例化一个显示子类,避免了直接应用原始的快速方法时,控制代码分散在每一个具体Form类中的问题。 <!--[if !supportLists]-->4、 <!--[endif]-->对显示数据的业务信息份进行了集中,当要求显示的信息发生变化时,只需在数据显示子类这一个类中更改即可。 此通用类结构仍有些不足之处,欢迎有兴趣的朋友继续完善: <!--[if !supportLists]-->1、<!--[endif]-->每个应用层类的外部调用方式非常类似(请参考开发的示例源码),表明,有些通用的方法没有进行更好的抽象。 <!--[if !supportLists]-->2、<!--[endif]-->快速访问基类对其子类的行为抽象不充分,导致子类的应用层调用代码非常类似。当初这样设计的目的是想保持类结构有充分的可扩展性。其实完全可以将基类进行改良:将抽象的虚方法更换成接口,这样,基类实现的更好的封装,并且更好地满足了“向稳定的方向依赖”和“针对接口编程”的设计原则。这样,应用层还是要实例化一个自己业务需要的类来实现此接口。但Delphi的接口用起来不像是真正的接口,通常要从TInterfacedObject等类继承,大大限制了类结构层次的演化。(因为在不支持多继承的语言环境中,如果还想增加更高层次的抽象就不那么容易了)。 <!--[if !supportLists]-->3、<!--[endif]-->当前的版本还没有提供针对某列进行数据排序的功能。
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi co // 模块名称: Delphi之ListView显示控制类---外部应用层通用类定义单元 // 模块描述: ListView快速操作方法类 // 单元文件: unLVCommonClass.pas--->unLVQuickClass.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2005-09-26 // 修改历史: 2006-05-31 // 修改描述: 解决GetLVItemOrderByValue()的参数不灵活的问题 // 并解决Method 'Create' hides virtual method of base type 'TComponent'的问题 // 修改历史: 2006-06-16 // 修改描述: 增加通过TList来高速增加、更新、删除数据 // 先用吧,以后再优化和完善 // 修改历史: 2006-07-10 // 修改描述: 成功地将ListView的On // 修改历史: 2006-07-11 // 修改描述: 重大重构:将此类分成两个类:TLVCommonClass-->TLVCommonClass和TLVQuickClass, // 以遵循SRP原则 //------------------------------------------------------------------------------ unit unLVQuickClass; interface uses SysUtils,Classes,ComCtrls,Windows,Variants, unLVControler;
const SpecialItemOrder = -1; CSImg_Normal = 0; CSImg_Running = 1; GetColumnOrder = 0; type TLVQuickClass = class(TInterfacedObject) private cxxLVC:TCXXLVControler; lvDataList: TList; //为ListView的Item的Da class function GetListDataIndexByKey(const listData:TList;const aKey: variant):integer; //快速 procedure ClearLVDataList(); protected //注意:约定最后一项一定是ImageIndex //tmpList:TStringList; function InitListViewColumns(const displayName: array of string; const displayWidth: array of integer; var lvTemp:TListView):boolean; //子类必须实现 class function CheckFound(const pData:Pointer;const aKey:variant):boolean;virtual; abstract; class procedure ProcOnDataDetail(const pData:Pointer;var Item: TListItem);virtual; abstract; //快速方法 //[注意:新方法中lvList不要求传递参数,保留以兼容旧客户端版本] //将pData数据加入List中,实现向ListView增加数据行 function AddItemDataToListView(const pData:Pointer;const dataNumber:integer; var lvTemp:TListView):boolean; //; var lvList: TList=nil):boolean; //以aKey为关键值查找,并用pData数据更新List中满足条件的内存块,实现向ListView更新数据行 function UpdateItemDataToListView(const aKey:variant;const pData:Pointer;const dataNumber:integer; var lvTemp:TListView):boolean; //; var lvList: TList=nil):boolean; //以aKey为关键值查找,并用pData数据删除List中满足条件的内存块,实现向ListView删除数据行 function DeleteItemDataToListView(const aKey:variant;const pData:Pointer;const dataNumber:integer; var lvTemp:TListView):boolean; //; var lvList: TList=nil):boolean; //删除List中所有内存区,实现将ListView清空所有数据行 procedure DeleteAllListView(var lvTemp:TListView); //ListVisw的On procedure On //ListVisw的On function GetLVListCount():integer; public constructor Create();overload; destructor Destroy();override; end; implementation ...{ TLVQuickClass } function TLVQuickClass.AddItemDataToListView(const pData: Pointer; const dataNumber: integer; var lvTemp: TListView):boolean; //; var lvList: TList):boolean; var pTemp:Pointer; begin //注意:要影响性能 //lvTemp.Items.BeginUpdate(); Result := false; if NOT (Assigned(pData) and Assigned(lvTemp) and Assigned(lvDataList)) then Exit; //new(pTemp); GetMem(pTemp,dataNumber); lvTemp.OwnerData := true; CopyMemory(pTemp,pData,dataNumber); lvDataList.Add(pTemp); Result := true; //注意:要影响性能 //lvTemp.Items.Count := lvList.Count; //lvTemp.Items.EndUpdate(); end; procedure TLVQuickClass.ClearLVDataList(); var Loop:integer; pTemp:Pointer; begin if NOT (Assigned(lvDataList) and (lvDataList.Count > 0)) then Exit; for Loop := 0 to lvDataList.Count - 1 do begin pTemp := (lvDataList.Items[Loop]); if Assigned(pTemp) then FreeMem(pTemp); end; end; constructor TLVQuickClass.Create; begin inherited Create(); cxxLVC := TCXXLVControler.Create(); //tmpList := TStringList.Create(); lvDataList := TList.Create(); end; procedure TLVQuickClass.DeleteAllListView(var lvTemp: TListView); begin if NOT (Assigned(lvTemp) and Assigned(lvDataList) and (lvDataList.Count > 0)) then Exit; lvTemp.OwnerData := true; lvTemp.Items.BeginUpdate(); while (lvDataList.Count > 0) do begin Dispose(lvDataList[0]); lvDataList.Delete(0); end; lvTemp.Items.Count := lvDataList.Count; lvTemp.Items.EndUpdate(); end; function TLVQuickClass.DeleteItemDataToListView(const aKey: variant; const pData: Pointer; const dataNumber: integer; var lvTemp: TListView):boolean; //var lvList: TList): boolean; var colIndex:integer; begin //注意:要影响性能 //lvTemp.Items.BeginUpdate(); Result := false; if NOT (Assigned(pData) and Assigned(lvTemp) and Assigned(lvDataList) and (lvDataList.Count > 0)) then Exit; colIndex := GetListDataIndexByKey(lvDataList,aKey); if (colIndex <> SpecialItemOrder) and (colIndex >= 0) and (colIndex <= lvDataList.Count - 1) then begin Dispose(lvDataList[colIndex]); lvDataList.Delete(colIndex); Result := true; end; //注意:要影响性能 //lvTemp.Items.Count := lvList.Count; //lvTemp.Items.EndUpdate(); end; destructor TLVQuickClass.Destroy; begin ClearLVDataList(); if Assigned(lvDataList) then FreeAndNil(lvDataList); if Assigned(cxxLVC) then FreeAndNil(cxxLVC); //if Assigned(tmpList) then // FreeAndNil(tmpList); inherited Destroy; end; class function TLVQuickClass.GetListDataIndexByKey(const listData: TList; const aKey: variant): integer; var Loop:integer; begin Result := SpecialItemOrder; if NOT Assigned(listData) then Exit; if listData.Count <= 0 then Exit; for Loop := 0 to listData.Count - 1 do begin if CheckFound(listData[Loop],aKey) then begin Result := Loop; break; end; end; end; function TLVQuickClass.GetLVListCount(): integer; begin Result := 0; if Assigned(lvDataList) then Result := lvDataList.Count; end; function TLVQuickClass.InitListViewColumns(const displayName: array of string; const displayWidth: array of integer; var lvTemp: TListView): boolean; begin Result := false; if Assigned(cxxLVC) then begin cxxLVC.InitLVColumns(displayName,displayWidth,lvTemp); end; end; procedure TLVQuickClass.On var pTemp:Pointer; begin //以后要移到类中,做成回调 if NOT Assigned(lvDataList) then Exit; if lvDataList.Count <= 0 then Exit; if Item.Index > lvDataList.Count then Exit; pTemp := lvDataList[Item.Index]; ProcOnDataDetail(pTemp,Item); Item.ImageIndex := 1; Item.Da end; function TLVQuickClass.UpdateItemDataToListView(const aKey: variant; const pData: Pointer; const dataNumber: integer; var lvTemp: TListView):boolean; //var lvList: TList):boolean; var colIndex:integer; begin //注意:要影响性能 //lvTemp.Items.BeginUpdate(); Result := false; if NOT (Assigned(pData) and Assigned(lvTemp) and Assigned(lvDataList) and (lvDataList.Count > 0)) then Exit; colIndex := GetListDataIndexByKey(lvDataList,aKey); if (colIndex <> SpecialItemOrder) and (colIndex >= 0) and (colIndex <= lvDataList.Count - 1) then begin CopyMemory(lvDataList[colIndex],pData,dataNumber); Result := true; end; //注意:要影响性能 //lvTemp.Items.Count := lvList.Count; //lvTemp.Items.EndUpdate(); end; end.
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi co // 模块名称: Delphi之ListView显示控制类---应用层:Soft socket类定义单元 // 模块描述: // 单元文件: unLVSoftSocket.pas-->unLVSocket.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2005-09-26 // // 修改历史: 2006-06-16 // 修改描述: 增加通过TList来高速增加、更新、删除数据 // 先用吧,以后再优化和完善 // 修改历史: 2006-07-10 // 修改描述: 成功地将ListView的On // 修改历史: 2006-07-11 // 修改描述: 重大重构:将此类分成两个类:TLVSoftSocket-->TLVSocket和TLVQuickClass // 以遵循SRP原则 //------------------------------------------------------------------------------ unit unLVSocket; interface uses ComCtrls,Classes,SysUtils,Windows, unLVCommonClass,unLVDefine; type TLVSocket = class(TLVCommonClass) private //注意:此方法与顺序严重藕合 function SaveSerialStatusToStringList(const aSocketStatus:TSocketStatusInfo):boolean; protected class function CheckFound(const pData:Pointer;const aKey:variant):boolean;override; class procedure ProcOnDataDetail(const pData:Pointer;var Item: TListItem);override; public constructor Create(); destructor Destroy();override; procedure InitListView(var lvTemp:TListView); //传统方法 procedure AddToLVSocket(const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); procedure UpdateLVSocket(const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); procedure DeleteLVSocket(const aSocketStatus:TSocketStatusInfo;var lvTemp:TListView); end; implementation ...{ TLVSocket } procedure TLVSocket.AddToLVSocket( const aSocketStatus: TSocketStatusInfo; var lvTemp: TListView); begin if SaveSerialStatusToStringList(aSocketStatus) then begin AddDataToListView(tmpList,lvTemp); end; end; class function TLVSocket.CheckFound(const pData: Pointer; const aKey: variant): boolean; var p:^TSocketStatusInfo; begin p := pData; Result := (p.UniqueID = aKey); end; constructor TLVSocket.Create; begin inherited Create(); end; procedure TLVSocket.DeleteLVSocket( const aSocketStatus: TSocketStatusInfo; var lvTemp: TListView); begin if SaveSerialStatusToStringList(aSocketStatus) then begin DeleteDataFromListView(tmpList,lvTemp); end; end; destructor TLVSocket.Destroy; begin inherited Destroy; end; procedure TLVSocket.InitListView(var lvTemp: TListView); begin InitListViewColumns(SocketStrBuffer,SocketWidthBuffer,lvTemp); end; class procedure TLVSocket.ProcOnDataDetail(const pData: Pointer;var Item: TListItem); var pSocket:^TSocketStatusInfo; begin //这两个有什么不同? //CopyMemory(pSocket,pData,sizeof(TSocketStatusInfo)); pSocket := pData; Item.Caption := IntToStr(pSocket.GroupID); Item.SubItems.Add(IntToStr(pSocket.UniqueID)); Item.SubItems.Add(pSocket.IPAddress); //Item.SubItems.Add(IntToStr(pSocket.CommServerPort)); Item.SubItems.Add(pSocket.SubItemName); Item.SubItems.Add(pSocket.LoginTime); Item.SubItems.Add(pSocket.SendNumber); Item.SubItems.Add(pSocket.RecNumber); Item.SubItems.Add(pSocket.Remark); //Item.SubItems.Add(pSocket.IPAddress); //Item.SubItems.Add(pSocket.IPAddress); end; function TLVSocket.SaveSerialStatusToStringList( const aSocketStatus: TSocketStatusInfo): boolean; begin Result := false; if Assigned(tmpList) then begin tmpList.Clear(); tmpList.Add(IntToStr(aSocketStatus.GroupID)); tmpList.Add(IntToStr(aSocketStatus.UniqueID)); tmpList.Add(aSocketStatus.IPAddress); tmpList.Add(aSocketStatus.SubItemName); tmpList.Add(aSocketStatus.LoginTime); tmpList.Add(aSocketStatus.SendNumber); tmpList.Add(aSocketStatus.RecNumber); tmpList.Add(IntToStr(CSImg_Running)); Result := true; end; end; procedure TLVSocket.UpdateLVSocket( const aSocketStatus: TSocketStatusInfo; var lvTemp: TListView); begin if SaveSerialStatusToStringList(aSocketStatus) then begin UpdateDataFromListView(tmpList,lvTemp); end; end; end.
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi co // 模块名称: Delphi之ListView显示控制类---外部应用层通用类定义单元 // 模块描述: ListView传统操作方法类 // 单元文件: unLVCommonClass.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2005-09-26 // 修改历史: 2006-05-31 // 修改描述: 解决GetLVItemOrderByValue()的参数不灵活的问题 // 并解决Method 'Create' hides virtual method of base type 'TComponent'的问题 // 修改历史: 2006-06-16 // 修改描述: 增加通过TList来高速增加、更新、删除数据 // 先用吧,以后再优化和完善 // 修改历史: 2006-07-10 // 修改描述: 成功地将ListView的On // 修改历史: 2006-07-11 // 修改描述: 重大重构:将此类分成两个类:TLVCommonClass-->TLVCommonClass和TLVQuickClass // 以遵循SRP原则 //------------------------------------------------------------------------------ unit unLVCommonClass; interface uses SysUtils,Classes,ComCtrls,Windows,Variants, unLVControler,unLVInterface;
const SpecialItemOrder = -1; CSImg_Normal = 0; CSImg_Running = 1; GetColumnOrder = 0; type TLVCommonClass = class(TInterfacedObject,ILVControllor) private cxxLVC:TCXXLVControler; class function StrIsNumber(const str:PChar):boolean; function GetLVItemOrderByValue(const lvTemp:TListView;const aKeyValue:string;const columnOrder:integer=SpecialItemOrder):integer; procedure CommonListItemProcess(const dataList: TStringList;var liTemp:TListItem; const isUpdate: boolean); protected //注意:约定最后一项一定是ImageIndex tmpList:TStringList; function InitListViewColumns(const displayName: array of string; const displayWidth: array of integer; var lvTemp:TListView):boolean; function AddDataToListView(const dataList:TStringList;var lvTemp:TListView):boolean; function UpdateDataFromListView(const dataList:TStringList;var lvTemp:TListView):boolean; //注意:删除的键值默认以SubItem[0]为标准 function DeleteDataFromListView(const dataList:TStringList;var lvTemp:TListView):boolean; //子类必须实现 class function CheckFound(const pData:Pointer;const aKey:variant):boolean;virtual; abstract; class procedure ProcOnDataDetail(const pData:Pointer;var Item: TListItem);virtual; abstract;
public constructor Create();overload; destructor Destroy();override; end; implementation ...{ TLVCommonClass } function TLVCommonClass.AddDataToListView(const dataList: TStringList; var lvTemp: TListView): boolean; var liTemp:TListItem; begin Result := false; if dataList.Count > 0 then begin lvTemp.Items.BeginUpdate(); liTemp := lvTemp.Items.Add(); CommonListItemProcess(dataList,liTemp,false); //liTemp.Caption := dataList.Strings[dataIndex]; //Inc(dataIndex); //while (dataIndex < dataList.Count) do //begin // liTemp.SubItems.Add(dataList.Strings[dataIndex]); // Inc(dataIndex); //end; lvTemp.Items.EndUpdate(); Result := true; end; end; procedure TLVCommonClass.CommonListItemProcess(const dataList: TStringList; var liTemp: TListItem; const isUpdate: boolean); var dataIndex:integer; begin dataIndex := 0; liTemp.Caption := dataList.Strings[dataIndex]; Inc(dataIndex); while (dataIndex < dataList.Count) do begin if (dataIndex = dataList.Count - 1) and StrIsNumber(PChar(dataList.Strings[dataIndex])) then begin liTemp.ImageIndex := StrToInt(dataList.Strings[dataIndex]); end else begin if isUpdate then liTemp.SubItems[dataIndex-1] := dataList.Strings[dataIndex] else liTemp.SubItems.Add(dataList.Strings[dataIndex]); end; Inc(dataIndex); end; end; constructor TLVCommonClass.Create; begin inherited Create(); cxxLVC := TCXXLVControler.Create(); tmpList := TStringList.Create(); end; function TLVCommonClass.DeleteDataFromListView( const dataList: TStringList; var lvTemp: TListView): boolean; var colIndex:integer; // liTemp:TListItem; begin Result := false; if dataList.Count > 0 then begin colIndex := GetLVItemOrderByValue(lvTemp,dataList.Strings[GetColumnOrder+1],GetColumnOrder); if (colIndex <> SpecialItemOrder) and Assigned(cxxLVC)then begin cxxLVC.DeleteItemByIndex(lvTemp,colIndex); Result := true; end; end; end; destructor TLVCommonClass.Destroy; begin if Assigned(cxxLVC) then FreeAndNil(cxxLVC); if Assigned(tmpList) then FreeAndNil(tmpList); inherited Destroy; end; function TLVCommonClass.GetLVItemOrderByValue(const lvTemp: TListView; const aKeyValue: string; const columnOrder: integer): integer; var Loop:integer; isOK:boolean; begin Result := SpecialItemOrder; isOK := false; for Loop := 0 to lvTemp.Items.Count - 1 do begin if columnOrder <> SpecialItemOrder then begin if (columnOrder >= 0) and (columnOrder < lvTemp.Columns.Count) then isOK := (lvTemp.Items[Loop].SubItems[columnOrder] = aKeyValue); end else isOK := (lvTemp.Items[Loop].Caption = aKeyValue); if isOK then begin Result := Loop; break; end; end; end; function TLVCommonClass.InitListViewColumns(const displayName: array of string; const displayWidth: array of integer; var lvTemp: TListView): boolean; begin Result := false; if Assigned(cxxLVC) then begin cxxLVC.InitLVColumns(displayName,displayWidth,lvTemp); end; end; class function TLVCommonClass.StrIsNumber(const str: PChar): boolean; var p:Char; i:integer; function CheckHex(p:Char):boolean; var k:Byte; begin k := Ord(P); Result := ((k >= 48) and (k <= 57)) or ((k >= 65) and (k <= 70)) or ((k >= 97) and (k <= 102)); end; begin try Result := false; for i := 0 to Length(str)-1 do begin p := str[i]; Result := CheckHex(p); if NOT Result then break; end; except Result := false; end; end; function TLVCommonClass.UpdateDataFromListView( const dataList: TStringList; var lvTemp: TListView): boolean; var colIndex:integer; liTemp:TListItem; begin Result := false; if dataList.Count > 0 then begin colIndex := GetLVItemOrderByValue(lvTemp,dataList.Strings[GetColumnOrder+1],GetColumnOrder); if (colIndex <> SpecialItemOrder) then begin lvTemp.Items.BeginUpdate(); liTemp := lvTemp.Items[colIndex]; CommonListItemProcess(dataList,liTemp,true); //liTemp.Caption := dataList.Strings[dataIndex]; //Inc(dataIndex); //while (dataIndex < dataList.Count) do //begin // liTemp.SubItems[dataIndex-1] := dataList.Strings[dataIndex]; // Inc(dataIndex); //end; lvTemp.Items.EndUpdate(); Result := true; end; end; end; end. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论