搜档网
当前位置:搜档网 › Delphi ListView快速操作通用实现

Delphi ListView快速操作通用实现

网易 新闻
微博
邮箱
相册
有道
摄影
闪电邮
手机邮
印像派
梦幻人生

更多 博客 手机博客
博客搬家

LiveWriter写博
Word写博
邮件写博
短信写博

群博客
博客油菜地
博客话题
博客热点
博客圈子
找朋友 发现小组风格 群博客召集令创建博客 登录 关注 显示下一条 | 关闭 往事随风; 胡言乱语,休得当真了
导航
首页 日志 相册 音乐 收藏 博友 关于我 日志 hdw802
加博友 关注他
最新日志
FLASH AS学习资料收集整理(Delphi 中用 Xml 配置文档生在DELPHI中用TreeView控件从经过实战验证后的14个精品指大盘零漂移图预测顶、底部的Delphi中DLL的消息处理该作者的其他文章
博主推荐
相关日志
随机阅读
首页推荐
日本青年与我身患绝症的表妹结婚台湾政客的娱乐圈攻略北京街头邂逅最牛潮男,惊爆眼球!云南山区小学留守儿童们的心愿实拍广州同性恋亲友会三周年庆典(图)杨恒均:我找到了对付越南的致命武器更多>>
对“推广广告”提建议

2009年8月24日 HGE 系列教材(1) --- 简介
Delphi ListView快速操作通用实现2009-09-21 02:47:44| 分类: 软件开发 阅读462 评论1 字号:大中小 订阅
众所周知,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的OnData()事件的数据处理回调方法。下面是几个具体实现的子类的OverView:



具体的一个从此类继承下来的用于Socket界面显示的TLVQuickSocket的类Overvivw如下:



可以看出:子类实现了两个抽象的虚方法,其它的方法,都是根据业务需要,类用户自行增加的。

源码如下:



//------------------------------------------------------------------------------

//

// 产品名称: 成晓旭的个人软件Delphi源码库

// 产品版本: CXXSoft delphi code source lib 1.0

// 模块名称: Delphi之ListView显示控制类---应用层:Soft socket类定义单元

// 模块描述:

// 单元文件: unLVSoftSocket.pas-->unLVQuickSocket.pas

// 开发作者: 成晓旭

// 备注: 任何人使用此文件时,请保留此段自述文件,谢谢!

// 开发时间: 2005-09-26

//

// 修改历史: 2006-06-16

// 修改描述: 增加通过TList来高速增加、更新、删除数据

// 先用吧,以后再优化和完善

// 修

改历史: 2006-07-10

// 修改描述: 成功地将ListView的OnData事件的List对象移入此类中

// 修改历史: 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 OnDataEvent(Item: TListItem);

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.OnDataEvent(Item: TListItem);

begin

Self.OnDataToListView(Item);

end;



class procedure TLVQuickSocket.ProcOnDataDetail(const pData: Pointer;var Item: TListItem);

var

pSock

et:^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快速数据操作的优势:

1、 可以快速实现MVC模式,达到界面显示与业务逻辑的分离。在Controllor类中,实例化数据显示子类,调用相应方法即可实现显示数据的增、删、改。

2、 与原始的快速方法相比,封装了内存数据List,大大简化了List对象的操作(尤其是当有很多相同或者类似数据要求在不同Form的ListView中显示时),并减少了List的创建、数据操作、释放等操作时发生错误的可能性。

3、 简化了多个相同、类似数据显示的控制代码,针对每个份要显示的数据及ListView,只需要实例化一个显示子类,避免了直接应用原始的快速方法时,控制代码分散在每一个具体Form类中的问题。

4、 对显示数据的业务信息份进行了集中,当要求显示的信息发生变化时,只需在数据显示子类这一个类中更改即可。

此通用类结构仍有些不足之处,欢迎有兴趣的朋友继续完善:

1、每个应用层类的外部调用方式非常类似(请参考开发的示例源码),表明,有些通用的方法没有进行更好的抽象。

2、快速访问基类对其子类的行为抽象不充分,导致子类的应用层调用代码非常类似。当初这样设计的目的是想保持类结构有充分的可扩展性。其实完全可以将基类进行改良:将抽象的虚方法更换成接口,这样,基类实现的更好的封装,并且更好地满足了“向稳定的方向依赖”和“针对接口编程”的设计原则。这样,应用层还是要实例化一个自己业务需要的类来实现此接口。但Delphi的接口用起来不像是真正的接口,通常要从TInterfacedObject等类继承,大大限制了类结构层次的演化。(因为在不支持多继承的语言环境中,如果还想增加更高层次的抽象就不那么容易了)



3、当前的版本还没有提供针对某列进行数据排序的功能。



//------------------------------------------------------------------------------

//

// 产品名称: 成晓旭的个人软件Delphi源码库

// 产品版本: CXXSoft delphi code source lib 1.0

// 模块名称: 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的OnData事件的List对象移入此类中,并将其上移到其类

// 修改历史: 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的Data属性查询关键数据在TList中的索引号

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;

//; v

ar 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的OnData事件处理

procedure OnDataToListView(var Item: TListItem);

//ListVisw的OnData事件的List Count

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.OnDataToListView(var Item: TListItem);

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.Data := pTemp;

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 code source lib 1.0

// 模块名称: Delphi之ListView显示控制类---应用层:Soft socket类定义单元

// 模块描述:

// 单元文件: unLVSoftSocket.pas-->unLVSocket.pas

// 开发作者: 成晓旭

// 备注: 任何人使用此文件时,请保留此段自述文件,谢谢!

// 开发时间: 2005-09-26

//

// 修改历史: 2006-06-16

// 修改描述: 增加通过TList来高速增加、更新、删除数据

// 先用吧,以后再优化和完善

// 修改历史: 2006-07-10

// 修改描述: 成功地将ListView的OnData事件的List对象移入此类中

// 修改历史: 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(https://www.sodocs.net/doc/044115172.html,mServerPort));

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 code source lib 1.0

// 模块名称: 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来高速增加、更新、删除数据

// 先用吧,以后再优化和完善

// 修改历史: 200

6-07-10

// 修改描述: 成功地将ListView的OnData事件的List对象移入此类中,并将其上移到其类

// 修改历史: 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 https://www.sodocs.net/doc/044115172.html,monListItemProcess(const dataList: TStringList;

var liTemp: TListItem; const isUpdate: boolean);

var

dataIndex:integer;

begin

dataIndex := 0;

liTemp.Caption := dataList.Strings[da

taIndex];

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

R

esult := 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.




评论这张 转发至微博 0人 | 分享到: 阅读(462)| 评论(1)| 引用 (0) |举报
2009年8月24日 HGE 系列教材(1) --- 简介
历史上的今天

相关文章

最近读者
登录后,您可以在此留下足迹。 cplm88 小永 changche killwolf whylove1 老茂 nkzx2010

评论
点击登录|昵称:
取消 验证码:换一张

04-18 03:54k
佩服楼猪的黑客精神。回复
上一页 1... -1-1-1-1-1-1-1... -1下一页 页脚
公司简介 - 联系方法 - 招聘信息 - 客户服务 - 隐私政策 - 博客风格 - 手机博客 - 订阅此博客
网易公司版权所有 ?1997-2011

相关主题