Delphi ListView快速操作通用实现
作者:成晓旭
众所周知,Delphi ListView类直接进行Add、Update、Delete操作的速度是比较慢的,尤其是当数据量较大时,比如数据量达到5000、10000、50000时,速度真是可以说是“慢得惊人”。其实快速操作的方法非常简单,就当大家都知道了。在本人的工作中,很多项目都用到ListView,并且对速度的响应要求比较高,于是发生了快速操作ListView的代码散布于多个项目大量模块中的问题,并且,当界面层数据显示要求发生改变时,自然发生“重复性代码的通用问题”。考虑到对以前版本的兼容性问题,也一直没有引用第三方的成熟组件。鉴于:“程序中的重复代码最易引发问题,必须消除”的实践经验,自己设计了一个比较通用的解决此类问题的类结构。当然,远不是什么“通用框架”了(眼下市面上很多人喜欢把自己做的无论什么东西通称为框架)。在采用此结构的项目中,很容易实现MVC模式,达到业务逻辑与界面显示分离的低级的、基础的要求。
(因为,目前CSDN的软件上传功能不可用,我只有将部分代码片断放在文档中,有需要完整源码者,请留言)
类层次结构:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/classStruct.png)
ListView基础操作封装在LVControler包中,核心的类是TCXXLVControler:
(说明:LVControler类是被封装通用类结构内,外部用户是不需要了解和访问的,所以不作介绍。)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/LVControler.png)
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 414.75pt; HEIGHT: 281.25pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png" o:title="LVControler"></imagedata></shape>
传统的ListView操作基类是TLVCommonClass,如果想用传统的方法增、删、改ListView中的数据,可以直接从此类继承。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/CommonClass.png)
<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 372pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image003.png" o:title="CommonClass"></imagedata></shape>
源码如下:
具体的一个从此类继承下来的用于Socket界面显示的TLVSocket的类Overvivw如下:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/commonSocket.png)
<shape id="_x0000_i1027" style="WIDTH: 367.5pt; HEIGHT: 315pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image005.png" o:title="commonSocket"></imagedata></shape>
源码如下:
快速的ListView操作基类是TLVQuickClass,如果想用快速方法增、删、改ListView中的数据,可以直接从此类继承。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/quickClass.png)
<shape id="_x0000_i1028" style="WIDTH: 414.75pt; HEIGHT: 397.5pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image007.png" o:title="quickClass"></imagedata></shape>
主要方法:(可以看到,里面没有真正的Public方法,子类也仅需实现两个Protected的virtual方法)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/method.JPG)
<shape id="_x0000_i1057" style="WIDTH: 414.75pt; HEIGHT: 370.5pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image012.png" o:title="method"></imagedata></shape>
源码如下:
此类中,要求每个具体应用的子类必须实现的方法仅有两个:CheckFound():根据具体应用检测的数据是否已经存在;ProcOnDataDetail():客户端ListView的OnData()事件的数据处理回调方法。下面是几个具体实现的子类的OverView:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/Quick%20Client.png)
<shape id="_x0000_i1055" style="WIDTH: 414.75pt; HEIGHT: 303.75pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image014.png" o:title="Quick Client"></imagedata></shape>
具体的一个从此类继承下来的用于Socket界面显示的TLVQuickSocket的类Overvivw如下:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/CXXSoft/quick%20socket.png)
<shape id="_x0000_i1056" style="WIDTH: 415.5pt; HEIGHT: 291pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/CHENGX~1/LOCALS~1/Temp/msohtml1/01/clip_image016.png" o:title="quick socket"></imagedata></shape>
可以看出:子类实现了两个抽象的虚方法,其它的方法,都是根据业务需要,类用户自行增加的。
源码如下:
//
------------------------------------------------------------------------------
//
//
产品名称:成晓旭的个人软件Delphi源码库
//
产品版本:CXXSoftdelphicodesourcelib1.0
//
模块名称:Delphi之ListView显示控制类---应用层:Softsocket类定义单元
//
模块描述:
//
单元文件:unLVSoftSocket.pas-->unLVQuickSocket.pas
//
开发作者:成晓旭
//
备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//
开发时间:2005-09-26
//
//
修改历史:2006-06-16
//
修改描述:增加通过TList来高速增加、更新、删除数据
//
先用吧,以后再优化和完善
//
修改历史:2006-07-10
//
修改描述:成功地将ListView的OnData事件的List对象移入此类中
//
修改历史:2006-07-11
//
修改描述:重大重构:将此类分成两个类:TLVSoftSocket-->TLVSoftSocket和TLVQuickSocket
//
以遵循SRP原则
//
------------------------------------------------------------------------------
unitunLVQuickSocket;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
interface
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
uses
ComCtrls,Classes,SysUtils,Windows,
unLVQuickClass,unLVDefine;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
type
TLVQuickSocket
=
class
(TLVQuickClass)
private
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
protected
class
functionCheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;override;
class
procedureProcOnDataDetail(
const
pData:Pointer;varItem:TListItem);override;
public
constructorCreate();
destructorDestroy();override;
procedureInitListView(varlvTemp:TListView);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
快速方法
//
暂时这样增加,以后在重构到基类中
procedureAddToLVSocketQuick(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
procedureUpdateLVSocketQuick(
const
aUniqueID:integer;
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
procedureDeleteLVSocketQuick(
const
aUniqueID:integer;
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
procedureDeleteAllLVSocket(varlvTemp:TListView);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureOnDataEvent(Item:TListItem);
functionGetDataCount():integer;
end;
implementation
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...
{TLVQuickSocket}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.AddToLVSocketQuick(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
AddItemDataToListView(@aSocketStatus,sizeof(aSocketStatus),lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
functionTLVQuickSocket.CheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;
var
p:
^
TSocketStatusInfo;
begin
p:
=
pData;
Result:
=
(p.UniqueID
=
aKey);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
constructorTLVQuickSocket.Create;
begin
inheritedCreate();
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.DeleteAllLVSocket(varlvTemp:TListView);
begin
DeleteAllListView(lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.DeleteLVSocketQuick(
const
aUniqueID:integer;
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
DeleteItemDataToListView(aUniqueID,@aSocketStatus,sizeof(aSocketStatus),lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
destructorTLVQuickSocket.Destroy;
begin
inheritedDestroy;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickSocket.GetDataCount():integer;
begin
Result:
=
Self.GetLVListCount();
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.InitListView(varlvTemp:TListView);
begin
InitListViewColumns(SocketStrBuffer,SocketWidthBuffer,lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.OnDataEvent(Item:TListItem);
begin
Self.OnDataToListView(Item);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
procedureTLVQuickSocket.ProcOnDataDetail(
const
pData:Pointer;varItem: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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickSocket.UpdateLVSocketQuick(
const
aUniqueID:integer;
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
UpdateItemDataToListView(aUniqueID,@aSocketStatus,sizeof(aSocketStatus),lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
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源码库
//
产品版本:CXXSoftdelphicodesourcelib1.0
//
模块名称:Delphi之ListView显示控制类---外部应用层通用类定义单元
//
模块描述:ListView快速操作方法类
//
单元文件:unLVCommonClass.pas--->unLVQuickClass.pas
//
开发作者:成晓旭
//
备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//
开发时间:2005-09-26
//
修改历史:2006-05-31
//
修改描述:解决GetLVItemOrderByValue()的参数不灵活的问题
//
并解决Method'Create'hidesvirtualmethodofbasetype'TComponent'的问题
//
修改历史:2006-06-16
//
修改描述:增加通过TList来高速增加、更新、删除数据
//
先用吧,以后再优化和完善
//
修改历史:2006-07-10
//
修改描述:成功地将ListView的OnData事件的List对象移入此类中,并将其上移到其类
//
修改历史:2006-07-11
//
修改描述:重大重构:将此类分成两个类:TLVCommonClass-->TLVCommonClass和TLVQuickClass,
//
以遵循SRP原则
//
------------------------------------------------------------------------------
unitunLVQuickClass;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
interface
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
uses
SysUtils,Classes,ComCtrls,Windows,Variants,
unLVControler;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
const
SpecialItemOrder
=
-
1
;
CSImg_Normal
=
0
;
CSImg_Running
=
1
;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
GetColumnOrder
=
0
;
type
TLVQuickClass
=
class
(TInterfacedObject)
private
cxxLVC:TCXXLVControler;
lvDataList:TList;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
为ListView的Item的Data属性查询关键数据在TList中的索引号
class
functionGetListDataIndexByKey(
const
listData:TList;
const
aKey:variant):integer;
//
快速
procedureClearLVDataList();
protected
//
注意:约定最后一项一定是ImageIndex
//
tmpList:TStringList;
functionInitListViewColumns(
const
displayName:arrayofstring;
const
displayWidth:arrayofinteger;
varlvTemp:TListView):
boolean
;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
子类必须实现
class
functionCheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;virtual;
abstract
;
class
procedureProcOnDataDetail(
const
pData:Pointer;varItem:TListItem);virtual;
abstract
;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
快速方法
//
[注意:新方法中lvList不要求传递参数,保留以兼容旧客户端版本]
//
将pData数据加入List中,实现向ListView增加数据行
functionAddItemDataToListView(
const
pData:Pointer;
const
dataNumber:integer;
varlvTemp:TListView):
boolean
;
//
;varlvList:TList=nil):boolean;
//
以aKey为关键值查找,并用pData数据更新List中满足条件的内存块,实现向ListView更新数据行
functionUpdateItemDataToListView(
const
aKey:variant;
const
pData:Pointer;
const
dataNumber:integer;
varlvTemp:TListView):
boolean
;
//
;varlvList:TList=nil):boolean;
//
以aKey为关键值查找,并用pData数据删除List中满足条件的内存块,实现向ListView删除数据行
functionDeleteItemDataToListView(
const
aKey:variant;
const
pData:Pointer;
const
dataNumber:integer;
varlvTemp:TListView):
boolean
;
//
;varlvList:TList=nil):boolean;
//
删除List中所有内存区,实现将ListView清空所有数据行
procedureDeleteAllListView(varlvTemp:TListView);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
ListVisw的OnData事件处理
procedureOnDataToListView(varItem:TListItem);
//
ListVisw的OnData事件的ListCount
functionGetLVListCount():integer;
public
constructorCreate();overload;
destructorDestroy();override;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
implementation
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...
{TLVQuickClass}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickClass.AddItemDataToListView(
const
pData:Pointer;
const
dataNumber:integer;varlvTemp:TListView):
boolean
;
//
;varlvList:TList):boolean;
var
pTemp:Pointer;
begin
//
注意:要影响性能
//
lvTemp.Items.BeginUpdate();
Result:
=
false
;
if
NOT(Assigned(pData)andAssigned(lvTemp)andAssigned(lvDataList))thenExit;
//
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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickClass.ClearLVDataList();
var
Loop:integer;
pTemp:Pointer;
begin
if
NOT(Assigned(lvDataList)and(lvDataList.Count
>
0
))thenExit;
for
Loop:
=
0
tolvDataList.Count
-
1
do
begin
pTemp:
=
(lvDataList.Items[Loop]);
if
Assigned(pTemp)then
FreeMem(pTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
constructorTLVQuickClass.Create;
begin
inheritedCreate();
cxxLVC:
=
TCXXLVControler.Create();
//
tmpList:=TStringList.Create();
lvDataList:
=
TList.Create();
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickClass.DeleteAllListView(varlvTemp:TListView);
begin
if
NOT(Assigned(lvTemp)andAssigned(lvDataList)and(lvDataList.Count
>
0
))thenExit;
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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickClass.DeleteItemDataToListView(
const
aKey:variant;
const
pData:Pointer;
const
dataNumber:integer;varlvTemp:TListView):
boolean
;
//
varlvList:TList):boolean;
var
colIndex:integer;
begin
//
注意:要影响性能
//
lvTemp.Items.BeginUpdate();
Result:
=
false
;
if
NOT(Assigned(pData)andAssigned(lvTemp)andAssigned(lvDataList)and(lvDataList.Count
>
0
))thenExit;
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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
destructorTLVQuickClass.Destroy;
begin
ClearLVDataList();
if
Assigned(lvDataList)then
FreeAndNil(lvDataList);
if
Assigned(cxxLVC)then
FreeAndNil(cxxLVC);
//
ifAssigned(tmpList)then
//
FreeAndNil(tmpList);
inheritedDestroy;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
functionTLVQuickClass.GetListDataIndexByKey(
const
listData:TList;
const
aKey:variant):integer;
var
Loop:integer;
begin
Result:
=
SpecialItemOrder;
if
NOTAssigned(listData)thenExit;
if
listData.Count
<=
0
thenExit;
for
Loop:
=
0
tolistData.Count
-
1
do
begin
if
CheckFound(listData[Loop],aKey)then
begin
Result:
=
Loop;
break
;
end;
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickClass.GetLVListCount():integer;
begin
Result:
=
0
;
if
Assigned(lvDataList)then
Result:
=
lvDataList.Count;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickClass.InitListViewColumns(
const
displayName:arrayofstring;
const
displayWidth:arrayofinteger;varlvTemp:TListView):
boolean
;
begin
Result:
=
false
;
if
Assigned(cxxLVC)then
begin
cxxLVC.InitLVColumns(displayName,displayWidth,lvTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVQuickClass.OnDataToListView(varItem:TListItem);
var
pTemp:Pointer;
begin
//
以后要移到类中,做成回调
if
NOTAssigned(lvDataList)thenExit;
if
lvDataList.Count
<=
0
thenExit;
if
Item.Index
>
lvDataList.CountthenExit;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
pTemp:
=
lvDataList[Item.Index];
ProcOnDataDetail(pTemp,Item);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
Item.ImageIndex:
=
1
;
Item.Data:
=
pTemp;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVQuickClass.UpdateItemDataToListView(
const
aKey:variant;
const
pData:Pointer;
const
dataNumber:integer;varlvTemp:TListView):
boolean
;
//
varlvList:TList):boolean;
var
colIndex:integer;
begin
//
注意:要影响性能
//
lvTemp.Items.BeginUpdate();
Result:
=
false
;
if
NOT(Assigned(pData)andAssigned(lvTemp)andAssigned(lvDataList)and(lvDataList.Count
>
0
))thenExit;
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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
end.
//
------------------------------------------------------------------------------
//
//
产品名称:成晓旭的个人软件Delphi源码库
//
产品版本:CXXSoftdelphicodesourcelib1.0
//
模块名称:Delphi之ListView显示控制类---应用层:Softsocket类定义单元
//
模块描述:
//
单元文件:unLVSoftSocket.pas-->unLVSocket.pas
//
开发作者:成晓旭
//
备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//
开发时间:2005-09-26
//
//
修改历史:2006-06-16
//
修改描述:增加通过TList来高速增加、更新、删除数据
//
先用吧,以后再优化和完善
//
修改历史:2006-07-10
//
修改描述:成功地将ListView的OnData事件的List对象移入此类中
//
修改历史:2006-07-11
//
修改描述:重大重构:将此类分成两个类:TLVSoftSocket-->TLVSocket和TLVQuickClass
//
以遵循SRP原则
//
------------------------------------------------------------------------------
unitunLVSocket;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
interface
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
uses
ComCtrls,Classes,SysUtils,Windows,
unLVCommonClass,unLVDefine;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
type
TLVSocket
=
class
(TLVCommonClass)
private
//
注意:此方法与顺序严重藕合
functionSaveSerialStatusToStringList(
const
aSocketStatus:TSocketStatusInfo):
boolean
;
protected
class
functionCheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;override;
class
procedureProcOnDataDetail(
const
pData:Pointer;varItem:TListItem);override;
public
constructorCreate();
destructorDestroy();override;
procedureInitListView(varlvTemp:TListView);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
//
传统方法
procedureAddToLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
procedureUpdateLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
procedureDeleteLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
end;
implementation
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...
{TLVSocket}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVSocket.AddToLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
if
SaveSerialStatusToStringList(aSocketStatus)then
begin
AddDataToListView(tmpList,lvTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
functionTLVSocket.CheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;
var
p:
^
TSocketStatusInfo;
begin
p:
=
pData;
Result:
=
(p.UniqueID
=
aKey);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
constructorTLVSocket.Create;
begin
inheritedCreate();
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVSocket.DeleteLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
if
SaveSerialStatusToStringList(aSocketStatus)then
begin
DeleteDataFromListView(tmpList,lvTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
destructorTLVSocket.Destroy;
begin
inheritedDestroy;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVSocket.InitListView(varlvTemp:TListView);
begin
InitListViewColumns(SocketStrBuffer,SocketWidthBuffer,lvTemp);
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
procedureTLVSocket.ProcOnDataDetail(
const
pData:Pointer;varItem: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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVSocket.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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVSocket.UpdateLVSocket(
const
aSocketStatus:TSocketStatusInfo;varlvTemp:TListView);
begin
if
SaveSerialStatusToStringList(aSocketStatus)then
begin
UpdateDataFromListView(tmpList,lvTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
end.
//
------------------------------------------------------------------------------
//
//
产品名称:成晓旭的个人软件Delphi源码库
//
产品版本:CXXSoftdelphicodesourcelib1.0
//
模块名称:Delphi之ListView显示控制类---外部应用层通用类定义单元
//
模块描述:ListView传统操作方法类
//
单元文件:unLVCommonClass.pas
//
开发作者:成晓旭
//
备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//
开发时间:2005-09-26
//
修改历史:2006-05-31
//
修改描述:解决GetLVItemOrderByValue()的参数不灵活的问题
//
并解决Method'Create'hidesvirtualmethodofbasetype'TComponent'的问题
//
修改历史:2006-06-16
//
修改描述:增加通过TList来高速增加、更新、删除数据
//
先用吧,以后再优化和完善
//
修改历史:2006-07-10
//
修改描述:成功地将ListView的OnData事件的List对象移入此类中,并将其上移到其类
//
修改历史:2006-07-11
//
修改描述:重大重构:将此类分成两个类:TLVCommonClass-->TLVCommonClass和TLVQuickClass
//
以遵循SRP原则
//
------------------------------------------------------------------------------
unitunLVCommonClass;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
interface
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
uses
SysUtils,Classes,ComCtrls,Windows,Variants,
unLVControler,unLVInterface;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
const
SpecialItemOrder
=
-
1
;
CSImg_Normal
=
0
;
CSImg_Running
=
1
;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
GetColumnOrder
=
0
;
type
TLVCommonClass
=
class
(TInterfacedObject,ILVControllor)
private
cxxLVC:TCXXLVControler;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
functionStrIsNumber(
const
str:PChar):
boolean
;
functionGetLVItemOrderByValue(
const
lvTemp:TListView;
const
aKeyValue:string;
const
columnOrder:integer
=
SpecialItemOrder):integer;
procedureCommonListItemProcess(
const
dataList:TStringList;varliTemp:TListItem;
const
isUpdate:
boolean
);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
protected
//
注意:约定最后一项一定是ImageIndex
tmpList:TStringList;
functionInitListViewColumns(
const
displayName:arrayofstring;
const
displayWidth:arrayofinteger;
varlvTemp:TListView):
boolean
;
functionAddDataToListView(
const
dataList:TStringList;varlvTemp:TListView):
boolean
;
functionUpdateDataFromListView(
const
dataList:TStringList;varlvTemp:TListView):
boolean
;
//
注意:删除的键值默认以SubItem[0]为标准
functionDeleteDataFromListView(
const
dataList:TStringList;varlvTemp:TListView):
boolean
;
//
子类必须实现
class
functionCheckFound(
const
pData:Pointer;
const
aKey:variant):
boolean
;virtual;
abstract
;
class
procedureProcOnDataDetail(
const
pData:Pointer;varItem:TListItem);virtual;
abstract
;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
public
constructorCreate();overload;
destructorDestroy();override;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
implementation
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...
{TLVCommonClass}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVCommonClass.AddDataToListView(
const
dataList:TStringList;
varlvTemp: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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedureTLVCommonClass.CommonListItemProcess(
const
dataList:TStringList;
varliTemp: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
)andStrIsNumber(PChar(dataList.Strings[dataIndex]))then
begin
liTemp.ImageIndex:
=
StrToInt(dataList.Strings[dataIndex]);
end
else
begin
if
isUpdatethen
liTemp.SubItems[dataIndex
-
1
]:
=
dataList.Strings[dataIndex]
else
liTemp.SubItems.Add(dataList.Strings[dataIndex]);
end;
Inc(dataIndex);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
constructorTLVCommonClass.Create;
begin
inheritedCreate();
cxxLVC:
=
TCXXLVControler.Create();
tmpList:
=
TStringList.Create();
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVCommonClass.DeleteDataFromListView(
const
dataList:TStringList;varlvTemp: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)andAssigned(cxxLVC)then
begin
cxxLVC.DeleteItemByIndex(lvTemp,colIndex);
Result:
=
true
;
end;
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
destructorTLVCommonClass.Destroy;
begin
if
Assigned(cxxLVC)then
FreeAndNil(cxxLVC);
if
Assigned(tmpList)then
FreeAndNil(tmpList);
inheritedDestroy;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVCommonClass.GetLVItemOrderByValue(
const
lvTemp:TListView;
const
aKeyValue:string;
const
columnOrder:integer):integer;
var
Loop:integer;
isOK:
boolean
;
begin
Result:
=
SpecialItemOrder;
isOK:
=
false
;
for
Loop:
=
0
tolvTemp.Items.Count
-
1
do
begin
if
columnOrder
<>
SpecialItemOrderthen
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
isOKthen
begin
Result:
=
Loop;
break
;
end;
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVCommonClass.InitListViewColumns(
const
displayName:arrayofstring;
const
displayWidth:arrayofinteger;varlvTemp:TListView):
boolean
;
begin
Result:
=
false
;
if
Assigned(cxxLVC)then
begin
cxxLVC.InitLVColumns(displayName,displayWidth,lvTemp);
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
class
functionTLVCommonClass.StrIsNumber(
const
str:PChar):
boolean
;
var
p:Char;
i:integer;
functionCheckHex(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
toLength(str)
-
1
do
begin
p:
=
str[i];
Result:
=
CheckHex(p);
if
NOTResultthen
break
;
end;
except
Result:
=
false
;
end;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
functionTLVCommonClass.UpdateDataFromListView(
const
dataList:TStringList;varlvTemp: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;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
end.