`
woxiaoe
  • 浏览: 284622 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

Delphi中的容器类

阅读更多
TList 类实际上就是一个可以存储指针的容器类,提供了一系列的方法和属性来添加,删除,重排,定位,存取和排序容器中的类,它是基于数组的机制来实现的容器,比较类似于C++中的Vector和Java中的ArrayList,TList 经常用来保存一组对象列表,基于数组实现的机制使得用下标存取容器中的对象非常快,但是随着容器中的对象的增多,插入和删除对象速度会直线下降,因此不适合频繁添加和删除对象的应用场景。下面是TList类的属性和方法说明:


属性
描述
Count: Integer;
返回列表中的项目数
Items[Index: Integer]: Pointer; default
通过以0为底的索引下标直接存取列表中的项目

方法
类型
描述
Add(Item: Pointer): Integer;
函数
用来向列表中添加指针
Clear;
过程
清空列表中的项目
Delete(Index: Integer);
过程
删除列表中对应索引的项目
IndexOf(Item: Pointer): Integer;
函数
返回指针在列表中的索引
Insert(Index: Integer; Item: Pointer);
过程
将一个项目插入到列表中的指定位置
Remove(Item: Pointer): Integer;
函数
从列表中删除指针

名称
类型
描述
Capacity: Integer;
property
可以用来获取或设定列表可以容纳的指针数目
Extract(Item: Pointer): Pointer;
function
Extract 类似于Remove 可以将指针从列表中删除,不同的是返回被删除的指针。 
Exchange(Index1, Index2: Integer);
procedure
交换列表中两个指针
First: Pointer;
function
返回链表中的第一个指针
Last: Pointer;
function
返回链表中最后一个指针
Move(CurIndex NewIndex: Integer);
procedure
将指针从当前位置移动到新的位置
Pack;
procedure
从列表中删除所有nil指针
Sort(Compare: TListSortCompare);
procedure
用来对链表中的项目进行排序,可以设定Compare参数为用户定制的排序函数

TObjectList 类


TObjectList = class(TList)

public

constructor Create(AOwnsObjects: Boolean); overload;

function Remove(AObject: TObject): Integer;

function FindInstanceOf(AClass: TClass;

Integer;

property OwnsObjects: Boolean;

end;

不同于TList类,TObjectList类的Add, Remove, IndexOf, Insert等方法都需要传递TObject对象作为参数,由于有了编译期的强类型检查,使得TObjectList比TList更适合保存对象。此外TObjectList对象有OwnsObjects属性。当设定为True (默认值),同TList类不同,TObjectList对象将销毁任何从列表中删除的对象。无论是调用Delete, Remove, Clear 方法,还是释放TObjectList对象,都将销毁列表中的对象。有了TObjectList类,我们就再也不用使用循环来释放了对象。这就避免了释放链表对象时,由于忘记释放链表中的对象而导致的内存泄漏。 另外要注意的是OwnsObjects属性不会影响到Extract方法,TObjectList的Extract方法行为类似于TList,只是从列表中移除对象引用,而不会销毁对象。

TObjectList 对象还提供了一个FindInstanceOf 函数,可以返回只有指定对象类型的对象实例在列表中的索引。如果AExact 参数为True,只有指定对象类型的对象实例会被定位,如果AExact 对象为False,AClass 的子类实例也将被定位。AStartAt 参数可以用来找到列表中的多个实例,只要每次调用FindInstanceOf 函数时,将起始索引加1,就可以定位到下一个对象,直到FindInstanceOf 返回-1。下面是代码示意:

var

begin

repeat

if idx >= 0 then

until(idx
TComponentList 类

TComponentList = class(TObjectList)

public

function Remove(AComponent: TComponent): Integer;

procedure Insert(Index: Integer; AComponent: TComponent);

end;

TClassList 类

TClassList = class(TList)

function GetItems(Index: Integer): TClass;

public

function Remove(aClass: TClass): Integer;

procedure Insert(Index: Integer; aClass: TClass);

read GetItems write SetItems; default;

不同于前面两个类,这个类继承于TList的类只是将Add, Remove, IndexOf, Insert和Items 调用的参数从指针换成了TClass元类类型。

Contnrs单元还定义了其它三个类:TOrderedList, TStack和TQueue,类型定义如下:

private

protected

...

function Count: Integer;

procedure Push(AItem: Pointer);

function Peek: Pointer;

TStack = class(TOrderedList)

procedure PushItem(AItem: Pointer); override;

TQueue = class(TOrderedList)

procedure PushItem(AItem: Pointer); override;

要注意虽然TOrderedList 并不是从TList继承的,但是它在内部的实现时,使用了TList来储存指针。另外注意TOrderedList类的PushItem 过程是一个抽象过程,所以我们无法实例化 TOrderedList 类,而应该从TOrderedList继承新的类,并实现抽象的PushItem方法。TStack 和 TQueue 正是实现了PushItem抽象方法的类, 我们可以实例化TStack 和TQueue类作为后进先出的堆栈 (LIFO)和先进先出的队列(FIFO)。下面是这两个的的方法使用说明: 

· AtLeast 可以用来检查链表的大小,判断当前列表中的指针数目是否大于传递的参数值,如果为True表示列表中的项目数大于传来的参数。 

· Pop返回链表的末端指针,并将其从链表中删除。 

TObjectStack和TObjectQueue类

TObjectStack = class(TStack)

procedure Push(AObject: TObject);

function Peek: TObject;

TObjectQueue = class(TQueue)

procedure Push(AObject: TObject);

function Peek: TObject;

这两个类只是TStack和TQueue 类的简单扩展,在链表中保存的是TObject的对象引用,而不是简单的指针。

到目前为止,我们看到的容器类中保存的都是指针或者对象引用(对象引用其实也是一种指针)。

unit IntList;

uses

type

protected

procedure SetItem(Index: Integer;

public

function Extract(Item: Integer): Integer;

function IndexOf(Item: Integer): Integer;

function Last: Integer;

procedure Sort;

read GetItem write SetItem; default;

implementation

function TIntList.Add(Item: Integer): Integer;

Result := inherited Add(Pointer(Item));

function TIntList.Extract(Item: Integer): Integer;

Result := Integer(inherited Extract(Pointer(Item)));

function TIntList.First: Integer;

Result := Integer(inherited First);

function TIntList.GetItem(Index: Integer): Integer;

Result := Integer(inherited Items[Index]);

function TIntList.IndexOf(Item: Integer): Integer;

Result := inherited IndexOf(Pointer(Item));

procedure TIntList.Insert(Index, Item: Integer);

inherited Insert(Index, Pointer(Item));

function TIntList.Last: Integer;

Result := Integer(inherited Last);

function TIntList.Remove(Item: Integer): Integer;

Result := inherited Remove(Pointer(Item));

procedure TIntList.SetItem(Index: Integer;

begin

end;

begin

Result := -1

Result := 1

Result := 0;

procedure TIntList.Sort;

inherited Sort(IntListCompare);

end.

Begin Listing Two - TMyObjectList

public

end;

protected

procedure SetItems(Index: Integer; AMyObject: TMyObject);

function Add(aMyObject: TMyObject): Integer;

function Remove(aMyObject: TMyObject): Integer;

procedure Insert(Index: Integer; aMyObject: TMyObject);

read GetItems write SetItems; default;

...

function TMyObjectList.Add(AMyObject: TMyObject): Integer;

Result := inherited Add(AMyObject);

procedure TMyObjectList.DoSomething;

i: Integer;

for i := 0 to Count-1 do

end;

begin

end;

Integer;

Result := inherited IndexOf(AMyObject);

procedure TMyObjectList.Insert(Index: Integer;

begin

end;

Integer;

Result := inherited Remove(AMyObject);

procedure TMyObjectList.SetItems(Index: Integer;

begin

end;

TStrings类

要注意的是TStrings类本身包含了很多抽象的纯虚的方法,因此不能实例化后直接使用,必须从TStrings类继承一个基类实现所有的抽象的纯虚方法来进行实际的字符串列表管理。虽然TStrings类本身是一个抽象类,但是它应该说是一个使用了Template模式的模版类,提供了很多事先定义好的算法来实现添加添加、删除列表中的字符串,按下标存取列表中的字符串,对列表中的字符串进行排序,将字符串保存到流中。将每个字符串同一个对象关联起来,提供了键-值对的关联等等。

var TempList: TStrings;

TempList := TStringList.Create;

TempList.Add(‘字符串1’);

finally

end;

TStrings类的应用非常广泛,很多VCL类的属性都是TStrings类型,比如TMemo组件的Lines属性,TListBox的Items属性等等。下面将介绍一下TStrings类的常见用法。

StringList1.Strings[0] := '字符串1';

StringList1[0] := '字符串1';

if FileListBox1.Items.IndexOf('TargetFileName') > -1 ...

procedure TForm1.Button1Click(Sender: TObject);var Index: Integer;

for Index := 0 to ListBox1.Items.Count - 1 do

end;

StringList1.Insert(2, 'Three');

StringList1.AddStrings(StringList2);

Memo1.Lines.Assign(ComboBox1.Items);

同对象关联

同视图交互

可以我们在TStrings和默认的实现类TStringList的源代码中却找不到同ListBox相关的代码,那么这种界面交互是如何做到的呢?

TListBoxStrings = class(TStrings)

ListBox: TCustomListBox;



function Add(const S: string): Integer; override;

procedure Delete(Index: Integer); override;

function IndexOf(const S: string): Integer; override;

procedure Move(CurIndex, NewIndex: Integer); override;

可以看到TListBoxStrings类实现了TStrings类的所有抽象方法,同时在内部有一个ListBox的私有变量。我们再看一下TListBoxStrings的Add方法:
function TListBoxStrings.Add(const S: string): Integer;
begin
Result := -1;
if ListBox.Style in [lbVirtual, lbVirtualOwnerDraw] then exit;
Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, Longint(PChar(S)));
if Result


可以看到TListBoxStrings在内部并没有保存添加的字符串,而是直接向Windows的原生列表盒控件发送消息实现的代码添加,而Windows的原生列表盒是一个MVC的组件,当内部的数据发生变化时,会自动改变视图显示,这就是为什么我们在设计器中输入的字符串会立刻显示在窗体列表框中的原因了。

还有一点要说明的是,Delphi的IDE只在使用Delphi的流机制保存组件到窗体设计文件DFM文件中的时,做了一些特殊的处理,能够自动保存和加载Published的TStrings类型的属性,下面就是一个ListBox储存在窗体设计文件DFM中文本形式示意(在窗体设计阶段,我们可以直接使用View As Text右键菜单命令看到下面的文本),我们可以注意到在设计时我们输入的Items的两个字符串被保存了起来:

Left = 64

Width = 145

ItemHeight = 16

'String1'

TabOrder = 1

随后如果运行程蚴保琕CL库会使用流从编译进可执行文件的DFM资源中将Items.Strings列表加载到界面上,这样就实现了设计是什么样,运行时也是什么样的所见即所得。

在实际开发过程中,我们经常会碰到类似于字典的定位操作的通过键查找相应值的操作,比如通过用户名查找用户相应的登陆密码等。在C++和Java中,标准模版库和JDK都提供了Map类来实现键-值机制,但是Delphi的VCL库却没有提供这样的类,但是TStrings类提供了一个简易的Map替代的实现,那就是Name-Value对。

var

Begin

//添加用户名-密码对

StringList1.Add(‘hubcat=bbb’);

//根据用户名hubdog查找密码

End;

THashedStringList类

Delphi6中提供的THashedStringList类没有提供任何的新的方法,只是对IndexOf和IndexOfName函数通过哈希表进行了性能优化,下面这个例子演示了TStringList和THashedStringList之间的性能差异:

unit CHash;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Inifiles;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
HashedList: THashedStringList;
DesList: TStringList;
List: TStringList;
public
{ Public declarations }
procedure Hash;
procedure Iterate;
end;
var
Form1: TForm1;

{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
I:Integer;
begin
Screen.Cursor := crHourGlass;
try
//初始化系统
for I := 0 to 5000 do
begin
HashedList.Add(IntToStr(i));
List.Add(IntToStr(i));
end;
Hash;
DesList.Clear;
Iterate;
finally
Screen.Cursor := crDefault;
end;
end;
procedure TForm1.Hash;
var
I, J: Integer;
begin
//基于哈希表的定位
for I := 3000 to 4000 do
begin
DesList.Add(IntToStr(HashedList.IndexOf(IntToStr(I))));
end;
end;
procedure TForm1.Iterate;
var
I, J: Integer;
begin
//基于遍历方式定位
for I := 3000 to 4000 do
begin
DesList.Add(IntToStr(List.IndexOf(IntToStr(I))));
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
HashedList := THashedStringList.Create;
DesList := TStringList.Create;
List := TStringList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
HashedList.Free;
DesList.Free;
List.Free;
end;

上面代码中的Hash过程,采用了新的THashedStringList类来实现的查找,而Iterate过程中使用了原来的TStringList类的IndexOfName来实现的查找。采用GpProfile(注:GpProfile的用法参见工具篇的性能分析工具GpProfile章节)对两个过程进行了性能比较后,从下图可以看到Hash执行同样查找动作只用了0.7%的时间,而Iterate方法则用了99.3%的时间,可以看到在字符串列表项目数在几千的数量级别时,基于哈希表的查询速度是原有方法的100多倍。
不过要说明的是,THashedStringList同TStringList类相比,虽然查找的速度

分享到:
评论

相关推荐

    Delphi中的容器类.doc

    Delphi中的容器类是编程中用于管理和操作数据集合的重要工具,它们提供了便利的方式来存储、访问和操作对象。本文主要讨论的是Delphi中的两种容器类:TList和TObjectList。 首先,TList类是一个基本的容器,它允许...

    delphi 注册方法加载TFrame容器

    在Delphi编程环境中,TFrame是一种非常实用的组件,它允许开发者将一组控件和代码封装成一个可重用的模块。本篇文章将详细讲解如何通过注册方法来加载TFrame容器,以及在D7(Delphi 7)中实现这个过程。 首先,我们...

    Delphi中的泛型基础及简单应用

    Delphi中的泛型基础及简单应用

    delphi帮助中文手册.rar

    1. **Delphi编程语言**:Delphi是一种基于Pascal语言的面向对象的编程语言,它提供了丰富的语法特性,如类、接口、异常处理等。Delphi的帮助手册会详细解释这些语言特性,以及如何在实际编程中运用它们来构建高效、...

    delphi 真正透明panel ,使用简单

    2. 在TyPanel类中重写Paint方法: - 在开始时调用Invalidate()方法,确保父窗体的区域被标记为需要重绘。 - 使用Canvas的SaveState()方法保存当前的绘图状态。 - 设置Canvas的ClippingRegion,使其只包含Panel的...

    Delphi 2010 透明Panel ListView

    在Delphi中,Panel是一个常用的容器控件,通常用于组织其他控件或提供背景。然而,原生的Panel控件不支持透明效果。为了实现透明,我们需要自定义控件,并调整其属性和绘图逻辑。在`TransPanel.dcu`中,开发者可能...

    delphi自定义控件菜单PopupMenu

    在Delphi编程环境中,自定义控件是提升应用程序功能和用户体验的重要手段。Popup Menu,即弹出式菜单,是用户界面中的一个常见元素,通常用于响应鼠标右键点击或者其他特定事件,显示一系列可选操作。在Delphi中,...

    delphi中判断子窗体是否打开

    在Delphi编程环境中,开发MDI(Multiple Document Interface)应用程序时,经常需要判断子窗体是否已经打开。MDI应用程序允许用户同时打开多个子窗口,这些子窗口在同一个父窗口(即MDI容器)内管理。在特定情况下,...

    Delphi2010语法手册.pdf

    此外,书中还列举了Delphi中常见的程序类型,如应用程序、服务、库和动态链接库(DLL)。这些程序类型的创建和运行方式各有特点,开发者可以根据实际需求选择合适的类型来构建自己的项目。 第二章深入探讨了Delphi...

    delphi动态创建的控件的Align问题altop按创建顺序依次下排

    `Align`属性是Delphi中TControl类的一个重要成员,用于控制控件相对于其父容器的对齐方式。它可以设置为以下几种值:`alNone`、`alTop`、`alBottom`、`alLeft`、`alRight`、`alClient`以及`alDock`系列(如`...

    delphi 真正实现实现pagecontrol多文档界面

    首先,PageControl组件是VCL库中的一个容器控件,它允许在同一个界面上切换多个TabSheet页面,每个TabSheet可以看作一个独立的文档区域。在实现MDI时,我们可以在PageControl的每个TabSheet上创建一个Form,以此模拟...

    Borland官方Delphi7 Vcl类属继承图.pdf

    它们是Delphi网络应用开发的基石,TWebModule是一个容器类,用于管理Web应用程序中页面处理逻辑;TWebRequestImpl负责实现Web请求,TWebSessionImpl则是会话管理的实现,用于跟踪不同用户请求间的状态。 此外,...

    Delphi中canvas(画布)运用

    `Canvas`是Delphi中的一个类,它主要负责在各种容器(如窗体、图片框等)上绘制图形和文本。通过`Canvas`对象,开发者可以控制绘制的颜色、线宽、字体等属性,并执行诸如绘制直线、矩形、圆形等操作。 #### 二、...

    属性容器类的对象持久化

    ### 属性容器类的对象持久化 #### 1. 问题背景与提出 在软件开发过程中,经常遇到需要处理各种文档管理的问题。一个典型的场景是构建一个文档管理系统,该系统能够支持不同类型的文档,并且每种文档可能具有不同的...

    Delphi PageControl组件用法

    Delphi PageControl组件是Delphi集成开发环境中一个非常重要的组件,尤其在开发具有多个页面或选项卡的应用程序时,它的作用不可忽视。PageControl组件允许你在单个窗口中组织多个同类型或不同类型的内容,每个页面...

    广联达Delphi笔试题

    TWinControl 是一个控件容器类,它可以包含其它控件。如果一个元件在运行时可见,它必须从 TControl 类派生。TControl 是一个可见控件类,它继承自 TWinControl。 2. 写出 TEdit、TLabel、TTimer 的主要继承路径。 ...

    delphi算法与数据结构

    在《Delphi算法与数据结构》这本书中,你可能会学到如何在Delphi中自定义数据结构,例如实现动态数组、链表和队列,以及如何利用Delphi的容器类(如TList、TArray、TDictionary等)来管理数据。同时,书中的实例可能...

    delphi面试题 delphi题目

    - 如果一个元件能作为其他元件的容器,它必须从(TWinControl)类派生。 - 如果一个元件在运行时可见,它必须从(TControl)类派生。 2. TEdit、TLabel、TTimer的主要继承路径: - TEdit -> TPersistent -> ...

    Delphi中的TList演示实例

    在Delphi编程环境中,TList是一个非常重要的容器类,它属于VCL(Visual Component Library)框架的一部分,用于存储和管理动态数组。这个类是基于动态数组实现的,提供了灵活的添加、删除、查找和遍历元素的功能。在...

    Delphi泛型库--DGL

    在DGL中,泛型主要体现在各种容器类和算法上,例如列表(List)、集合(Set)、映射(Map)和队列(Queue)等,它们都支持不同类型的元素,极大地提高了代码的灵活性和可维护性。 1. **泛型容器:** - **TList**:...

Global site tag (gtag.js) - Google Analytics