当前位置:编程学习 > Delphi >>

delphi容器类3

出于效率的考虑,Delphi并没有象C++和Java那样将字符串定义为类,因此TList本身不能直接存储字符串,而字符串列表又是使用非常广泛的,为此Borland提供了TStrings类作为存储字符串的基类,应该说是它除了TList类之外另外一个最重要的Delphi容器类。要注意的是TStrings类本身包含了很多抽象的纯虚的方法,因此不能实例化后直接使用,必须从TStrings类继承一个基类实现所有的抽象的纯虚方法来进行实际的字符串列表管理。虽然TStrings类本身是一个抽象类,但是它应该说是一个使用了Template模式的模版类,提供了很多事先定义好的算法来实现添加添加、删除列表中的字符串,按下标存取列表中的字符串,对列表中的字符串进行排序,将字符串保存到流中。将每个字符串同一个对象关联起来,提供了键-值对的关联等等。
    因为TStrings类本身是个抽象类,无法实例化,因此Delphi提供了一个TStringList的TStrings的子类提供了TStrings类的默认实现,通常在实际使用中,我们都应该使用TStringList类存储字符串列表,代码示意如下:
var   TempList: TStrings;     
begin
   TempList := TStringList.Create;
   try   
    TempList.Add(‘字符串1’);
      …
   finally   
    TempList.Free;     
   end;
end;

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

TStrings类的常见的用法

根据下标存取列表中的字符串是最常见的一种操作,用法示意如下:
   StringList1.Strings[0] := '字符串1';
     注意在Delphi中,几乎所有的列表的下标都是以0为底的,也就是说Strings[0]是列表中的第一个字符串。另外,由于Strings属性是字符串列表类的默认属性,因此可以省略Strings,直接用下面的简便方法存取字符串:
   StringList1[0] := '字符串1';

 

定位一个列表中特定的字符串的位置,可以使用IndexOf方法,IndexOf方法将会返回在字符串列表中的第一个匹配的字符串的索引值,如果没有匹配的字符串则返回-1。比如我们可以使用IndexOf方法来察看特定文件是否存在于文件列表框中,代码示意如下:

 

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

 

有一点不方便的是TStrings类没有提供一个方法可以查找除了第一个匹配字符串外其他同样匹配的字符串的索引,只能是自己遍历字符串列表来实现,这点不如C++中的模版容器类以及相关的模版算法强大和方便。下面是一个遍历字符串列表的示意,代码遍历列表框中的所有字符串,并将其全部转化为大写的字符串:

 

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

begin

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

ListBox1.Items[Index] := UpperCase(ListBox1.Items[Index]);

end;

 

前面我们看到了,要想向字符串列表中添加字符串,直接使用Add方法就可以了,但是Add方法只能将字符串加入到列表的末尾,要想在列表的指定位置添加字符串,需要使用Insert方法,下面代码在列表的索引为2的位置添加了字符串:

 

StringList1.Insert(2, 'Three');

 

如果要想将一个字符串列表中的所有字符串都添加到另一个字符串列表中,可以使用AddStrings方法,用法如下:

StringList1.AddStrings(StringList2); 

 

要想克隆一个字符串列表的所有内容,可以使用Assign方法,例如下面的方法将Combox1中的字符串列表复制到了Memo1中:

Memo1.Lines.Assign(ComboBox1.Items);

要注意的是使用了Assign方法后,目标字符串列表中原有的字符串会全部丢失。

 

同对象关联

 

前面说了我们可以将字符串同对象绑定起来,我们可以使用AddObject或者InsertObject方法向列表添加同字符串关联的对象,也可以通过Objects属性直接将对象同特定位置的字符串关联。此外TStrings类还提供了IndexOfObject方法返回指定对象的索引,同样的Delete,Clear和Move等方法也可以作用于对象。不过要注意的是我们不能向字符串中添加一个没有同字符串关联的对象。

 

同视图交互

 

刚刚学习使用Delphi的人都会为Delphi IDE的强大的界面交互设计功能所震惊,比如我们在窗体上放上一个ListBox,然后在object Inspector中双击它的Items属性(TStrings类型),在弹出的对话框中,见下图,我们输入一些字符串后,点击确定,关闭对话框,就会看到窗体上的ListBox中出现了我们刚才输入的字符串。

 

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

 

秘密就在于TListBox的Items属性类型实际上是TStrings的基类TListBoxStrings类,我们看一下这个类的定义:

 

   TListBoxStrings = class(TStrings)

   private

     ListBox: TCustomListBox;

   protected

   public

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

     procedure Clear; override;

     procedure Delete(Index: Integer); override;

     procedure Exchange(Index1, Index2: Integer); override;

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

     procedure Insert(Index: Integer; const S: string); override;

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

   end;

可以看到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 < 0 then raise EOutOfResources.Create(SInsertLineError);
end;


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

 

于是我们也就知道为什么Borland将TStrings设计为一个抽象的类而没有提供一个默认的存储方式,就是因为很多的界面组件在内部对数据的存储有很多不同的方式,Borland决定针对不同的组件提供不同的存储和交互方式。同样的我们要编写的组件如果有TStrings类型的属性,同时也要同界面或者其它资源交互的话,不要使用TStringList来实现,而应该从TStrings派生出新类来实现更好的交互设计。

 

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

 

   object ListBox1: TListBox

     Left = 64

     Top = 40

     Width = 145

     Height = 73

     ItemHeight = 16

     Items.Strings = (

       'String1'

       'String2')

     TabOrder = 1

   end

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

 

键-值对

 

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

 

对于TStrings来说,所谓的Name-Value对,实际上就是&r

补充:软件开发 , Delphi ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,