关于Tlist的属性,方法的问题。谢谢!(50分)

  • 主题发起人 主题发起人 夜风
  • 开始时间 开始时间

夜风

Unregistered / Unconfirmed
GUEST, unregistred user!
Tlist 是指针数组的列表,请问Tlist.capacity ,Tlist.count,Tlist.add(^p)的含义及用法。
试举例!谢谢!
 
其实用起来就跟LISTBOX差不多,只是这里加的是对象的指针而已,每次引用的时候
得强制转换一下而已,其实在C++ BUILDER里用起来更好一点。
 
Tlist.capacity 容量
Tlist.count有几个对象
Tlist.add(^p)增加一个对象,并返回其位置
var mybutton:tbutton;
temp:integer;
mylist:tlist;
begin
if mylist<>nil then
begin
mybutton:=tbutton.create(self);
mybutton.parent:=self;
temp:=mylist.add(mybutton);
with mybutton do
begin
top:=25;
left:=0;
caption:='asdfas';
onclick:= buttonindexofclick;
end;
end;

 
Tlist.capacity 可不用理它
Tlist.count 是真正保存的数量
Tlist.add(指针) 如果你的p是指针,那么Tlist.add(p) 不要^

 
用法例程之一可以用它实现控件数组,我想比利用控件的Tag属性更好吧。
 
to ugvanxk:
您说的很好!谢了!过后给你加分。
问题:关于Tlist的属性,方法的问题。谢谢! ( 积分:50, 回复:4, 阅读:27 )
分类:Object Pascal ( 版主:menxin, cAkk )
来自:夜风, 时间:2002-2-22 21:14:00, ID:936010 | 编辑 [显示:小字体 | 大字体]
Tlist 是指针数组的列表,请问Tlist.capacity ,Tlist.count,Tlist.add(^p)的含义及用法。
试举例!谢谢!





来自:ugvanxk, 时间:2002-2-22 21:25:00, ID:936027
Tlist.capacity 容量
Tlist.count有几个对象
Tlist.add(^p)增加一个对象,并返回其位置
var mybutton:tbutton;
temp:integer;
mylist:tlist;
begin
if mylist<>nil then
begin
mybutton:=tbutton.create(self);
mybutton.parent:=self;
temp:=mylist.add(mybutton);
with mybutton do
begin
top:=25;
left:=0;
caption:='asdfas';
onclick:= buttonindexofclick;
end;
end;

句中mybutton:=tbutton.create(self);可改为mybutton:=tbutton.create吗?初始化嘛!
对与参数self我也不太懂,能具体说名一下吗?



 
当然不能,你看看tbutton类的构造函数即可,它有一个输入参数 owner ,决定该button
的owner 控件是谁
 
给你装载一片tlist的文章,出自<<Delphi之未经证实的葵花宝典2.7>>

使用TList 表达
关系
吴艺文
在上一期里﹐高焕堂先生的文章 ──「Prototype 样式」使用了TList 容器物
件(container) 去包含多个图形小物件。但是他并没仔细说明TList 类别的功能和用法﹐
我猜想有些读者会想去了解如何活用TList 物件。因之﹐本文首先说明TList 物件之功能﹐
并进而运用它来表达OO软体中极常见的关系──Whole-part关系。本文将仔细介绍TList
类别﹐并说明如何表示物件间之关系(relationship)。
物件间的Whole-part关系

回想传统的软体师﹐常甚专注于撰写程序(procedure) 来处理某些资料(data)﹐较少关
心软体的整体结构(architecture)。在现在的OO软体中﹐把资料及其相关的程序结合在一起
﹐封装(encapsulate) 在物件之中。软体师在使用物件时﹐通常把物件视为黑箱(black-box
) ﹐不会关心于物件内部之细节﹔因之能专注于物件之间的关系。软体师的主要工作﹐就是
在于建立物件之间的互助合作(collaboration) 关系﹐为物件安排应尽之角色(role)﹐至于
物件内部之细节﹐反而不顶重要。如此﹐可让软体师着重于软体的整体架构上﹐而不会一头
栽进程式的执行细节之中。这避免了见树不见林的缺点﹐放宽了软体师的眼界﹐为软体的多
用途(reusability) 及弹性(flexibility) 着想﹐可创造长寿的软体﹗

物件之间的常见关系有许多种﹐其中之一就是Whole-part关系。像一朵花是由花蕊、花瓣、



图1 Form1 物件包含3 个控制物件



衬叶等所构成的﹐这朵花是个「整体」(Whole)﹐而花蕊、花瓣等则是这整体的「一部分」
(part)。

再如﹐图1 的Delphi 画面上﹐Form1 物件包含着3 个控制物件(control) ﹐这些控制物件
成为Form1 的一部分。因之﹐Form1 是个整体﹐而各控制物件则是Form1 物件的一部分。

我们可使用图形表示为﹕







图2 Whole-part关系与继承关系



这图包括了Whole-part关系﹐以及继承关系。

●菱形符号表示Whole-part关系﹔就是Form1 物件可包含有数个control 物件。

●箭头符号表示继承关系﹔就是control 物件可细分为数个种类。

由于篇幅的限制﹐本文专注于Whole-part关系﹐而不讨论继承关系。Whole-part关系可分为两种﹕

◎「部分」物件之个数是确定的。例如﹐1 辆汽车含有1 个方向盘﹐1 个Form物件含有1 个
抬头(
caption) 物件﹐1 只青蛙有4 条腿等等。在这种情形下﹐并不需要使用TList 容器物件来表示之
﹐而只需使用一般变数即行了。所以本文不拟讨论这种情形。

◎「部分」物件之个数是可变的。例如﹐1 个Form物件内含多个控制物件﹐1 棵树含有成千上万叶子
﹐1 位学生的成绩单上列有各科目的成绩等等。这种Whole-part关系通常得藉容器物件来表达之﹐
如Delphi 的TList 物件就可派上用场了。本文将详细说明如何表达这种关系。



认识TList 类别

在部分物件之个数不固定时﹐整体物件常内含「容器」(container) 物件﹐再由容器物
件来包含部分物件。例如﹐上述的Form1 物件与控制物件之间的关系﹐在程式中可表示为﹕



图 3 容器物件



由于Delphi的物件皆诞生在堆积(heap)中﹐皆属动态物件(dynamic object)。所以只能藉上
图的指标(pointer 或reference )来表达「包含」的概念﹐进而表达出Whole-part关系。

虽然Delphi所提供的通用性容器类别并不多﹐但TList 已足够表达出常见的Whole-part
关系了。首先介绍TList 类别的常用属性如下﹕

●公用变数Count ──记录目前容器内含多少个物件。

●Add(小物件)──将小物件存入容器物件之中。

●Delete(n) ──将容器内的第n 个物件删除。

●Items[n]──取出容器中的第n 个物件。

●Clear() ──删除掉所有的小物件﹐Count 值归零。



由下述的Delphi程式来说明这些功能。这程式定义Person类别来诞生物件﹐然后将这些物
件存入TList 之容器物件之中。程式内容是﹕



unit Aa01
interface uses

SysUtils, WinTypes, WinProcs, Messages,

Classes, Graphics, Controls, Forms, Dialogs;



{ === Person class === }

type Person = class(TObject)

public

constructor Create(na:string);

function Name : string;

private

pname : string;

end;



type TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

end;



var

Form1: TForm1;

implementation

{$R *.DFM}

constructor Person.Create(na:string);

begin pname := na
end;

function Person.Name : string;

begin Result := pname
end;

procedure TForm1.FormCreate(Sender: TObject);

var

p : Person
i : Integer;

str : string
list : TList;

begin

list := TList.Create;

list.Add( Person.Create('John') );

list.Add( Person.Create('Tom') );

p := list.Items[0];

list.Delete(0);

p.Destroy;

list.Add( Person.Create('Alvin') );

for i:=0 to list.Count-1 do

begin

p := list.Items;

MessageDlg( p.Name, mtInformation,

[mbOK],0);

end;

for i:=0 to list.Count-1 do

begin

p := list.Items;

p.Destroy;

end;

list.Destroy;

end;

end.

执行FormCreate()程序时﹐由TList 类别诞生容器物件﹐并由list代表之﹐如图4。





图 4 list代表容器物件

接着﹐由Person类别诞生物件﹐并将其指标存入容器物件之中﹐如图5。

图5 存取容器物件



list.Items[0] 取出容器中的#0物件﹐将其参考(reference) 给p ﹐如上图所示。list.
Delete(0)删除掉容器中的#0物件﹐即切断其指标(即reference )﹐如图6。

图 6 除掉容器中的物件



当容器的#0物件被删除后﹐原来的#1物件变成为#0物件了。同理﹐原来的#2物件则变为#1
物件﹐依此类推下去。Delete()只是除去容器中的指标而已﹐并非真正毁去该物件。至p.Destroy 才真正除去该物件。

接下去的Add() 再加入1 个物件﹐如图 7 。接下去﹐for 回圈依序读完容器的各小物件﹐并逐一输出其内部资料。另一个for 回圈则实际毁掉容器内含的物件。最后﹐list.Destroy毁去这容器物件。

图 7再加入1 个物件



简单的Whole-part关系

最单纯的Whole-part关系就是某物件「内含」(contain) 其它物件。例如﹐

1 张订单上面列示着多个采购的产品项目

1 支棒球队拥有数位教练及多位球员

学生的成绩单上印有多项成绩

1 篇文章是由许多句子所组成

萤幕上的选择表(menu)内含数个选择项

1 份考卷包含数十道考题



就拿订单(order form)的例子来说﹐订单上常列有多个采购项目(order line)。





图8 订单

每个采购项目通常包括有产品名称、采购数量、金额等。为了简单起见﹐假设采购项目只
含产品名称及金额两个项目﹐则可藉TList 容器物件来表示「订单」与「采购项目」之间
的Whole-part关系﹐如下图所示﹕





OO软体师通常皆会很习惯于掌握这种Whole-part关系﹐且常藉容器物件来表示之。请看实际
的Delphi程式﹐先定义Order 及OrderLine 两个类别﹕



unit Aa02
interface uses

SysUtils, WinTypes, WinProcs, Messages, Classes,

Graphics, Controls, Forms, Dialogs;



{ === Order class === }

type OrderLine = class(TObject)

public

constructor Create(pna:string
a:Real );

function Name : string;

function Amount : Real;

private

pname : string;

amt : Real;

end;



{ === Order === }

type Order = class(TObject)

public

constructor Create;

destructor Destroy
override;

procedure AddLine(var p:OrderLine);

function Amount : Real;

private

list : TList;

end;



在Order 类别中定义了list变数﹐其型态TList ﹐表示list将可代表1 个TList 之物件﹐
其本质上就是list变数,内含一个指标﹐可指向TList 之物件。在Order 类别的建构程序
Create负责诞生TList 物件﹐而由Order 的除构程序Destroy负责删除掉这TList 物件。各
程序之定义如下﹕



type TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

end;



var

Form1: TForm1;

implementation

{$R *.DFM}

constructor OrderLine.Create(pna:string
a:Real );

begin

pname := pna
amt := a;

end;

function OrderLine.Name : String;

begin Result := pname
end;

function OrderLine.Amount: Real;

begin Result := amt
end;

constructor Order.Create;

begin list := TList.Create
end;

destructor Order.Destroy;

begin list.Destroy
end;

function Order.Amount: Real;

var i:Integer
sum:Real
p : OrderLine;

begin

sum := 0;

for i:=0 to list.Count-1 do

begin

p := list.Items;

sum := sum + p.Amount;

end;

Result := sum;

end;



procedure Order.AddLine(var p:OrderLine);

begin list.Add(p)
end;

procedure TForm1.FormCreate(Sender: TObject);

var

ord : Order
pl : OrderLine;

str : string;

begin

ord := Order.Create;

pl := OrderLine.Create('Pencil',88.25);

ord.AddLine(pl);

pl := OrderLine.Create('Ballpen',110.5);

ord.AddLine(pl);

str := FloatToStr( ord.Amount );

MessageDlg(str, mtInformation, [mbOK],0);

end;

end.



Order 类别的Amount()程序计算出该订单的总金额。AddLine() 则在订单上新增一个采购项目。在FormCreate()中﹐ord 物件内含一个list物件﹐而list物件容纳2 个OrderLine 物件。如此就表达了订单与采购项目之间的Whole-part关系了。





递回式Whole-part关系



Whole-part关系内含别的Whole-part关系﹐且允许有多层次的Whole-part关系﹐
通称为递回式的Whole-part关系。在自然界中常见这种关系﹐例如﹐树叶是树的一部分﹐
但树叶又是个整体﹐其内含着叶脉、叶绿素等「部分」物件。







在企业界﹐最典型的例子是「物件结构表」(bill of material简称BOM)﹐如下﹕







在Delphi画面上﹐也常见这种Whole-part关系﹐如﹕







虽然这些结构似乎很复杂﹐但从这些图形中﹐可看出这些物件可依其角色而分为两类﹕



1. Leaf物件。如上图中的椭圆形所示之物件﹐它们不具有Whole 之角色﹐只具有part之
角色。这通称为「基本组件」(primitive component) 。



2. Composite 物件。如上图中的长方形所示之物件﹐它们具有Whole 之角色﹐也可能具
有part之角色。这通称为「复合组件」(composite component) 。



因之﹐以Delphi来表示时﹐只需定义两个类别──Leaf及Composite 类别即行。由于这两
类别皆为组件﹐所以可定义个父类别(super class) 图9。



图 9 递回Whole-part关系



递回Whole-part关系是很常见的﹐且上图所示的表示方法又是OO软体专家最常用的表
示法。

因之﹐在Gamma 的"Design Patterns" 一书〔注1 〕中﹐也将之收录为重要的「样式」
(Pattern) 之1。 该书所画的样式结构图如图10。











图10 Composite样式

样式是专家们最惯用的设计方式﹐这样式建议我们应定义Add() 、Remove()和GetChild()
三个基本的虚拟(virtual) 程序﹐以及其它的程序。专家们把这表示法视为样式﹐就意谓
着﹕这是专家们所认为最理想的表达方式。现在﹐实际以Delphi程式来表示上述的BOM
结构。首先定义三个类别﹕



unit Aa03
interface uses

SysUtils, WinTypes, WinProcs, Messages,

Classes, Graphics, Controls, Forms, Dialogs;



{ === Part class === }

type Part = class(TObject)

public

procedure Add(var p:Part)
virtual;

function GetChild(n:Integer):Part
virtual;

function Cost:Real
virtual;

protected

pna : string;

end;



type PiecePart = class(Part)

public

constructor Create(na:string
c:Real);

function Cost:Real
override;

procedure Add(var p:Part);override;

private

pcost : Real;

end;



type Assembly = class(Part)

public

constructor Create(na:string);

function Cost:Real
override;

procedure Add(var p:Part)
override;

function GetChild(n:Integer):Part
override;

private

list : TList;

end;



这表示了下述结构﹕







PiecePart 代表最下层的基本物件组件。而Assembly则代表中层的半成品物件组件﹐或
代表成品。Add() 、GetChild()和Cost()皆定义为虚拟(virtual)程序。在Assembly中利用
TList 物件来表达Whole-part关系。接下来﹐设计各程序﹕



type

TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

end;



var

Form1: TForm1;

implementation

{$R *.DFM}

constructor PiecePart.Create(na:string
c:Real);

begin pna := na
pcost := c
end;



function Part.Cost: Real;

begin end;



function PiecePart.Cost: Real;

begin Result := pcost
end;



constructor Assembly.Create(na:string);

begin list := TList.Create
pna:=na
end;



function Assembly.Cost: Real;

var i:Integer
sum:Real
p:Part;

begin

sum := 0;

for i:=0 to list.Count-1 do

begin

p := list.Items;

sum := sum + p.cost;

end;

Result := sum;

end;

procedure Part.Add(var p:Part);

begin end;

procedure Assembly.Add(var p:Part);

begin list.Add(p)
end;

procedure PiecePart.Add(var p:Part);

begin

MessageDlg('Parts do not have Subparts',

mtInformation, [mbOK],0);

end;

function Part.GetChild(n:Integer):Part;

begin Result := nil
end;



function Assembly.GetChild(n:Integer):Part;

begin Result := list.Items[n]
end;



procedure TForm1.FormCreate(Sender: TObject);

var

aly1, aly2, p1, p2 : Part
str:string;

begin

aly1 := Assembly.Create(‘bulb’);

p1 := PiecePart.Create(‘body’, 88.25);

aly1.Add(p1);

p1 := PiecePart.Create(,head,, 100.5);

aly1.Add(p1);

aly2 := Assembly.Create(‘ light’)


aly2.Add(aly1);

p1 := PiecePart.Create(‘cover’, 10.0)


aly2.Add(p1);

str := FloatToStr( aly2.Cost );

MessageDlg(str, mtInformation, [mbOK],0);

p1 := aly2.GetChild(0);

str := FloatToStr( p1.Cost );

MessageDlg(str, mtInformation, [mbOK],0);

p2 := p1.GetChild(1);

str := FloatToStr( p2.Cost );

MessageDlg(str, mtInformation, [mbOK],0);

end;

end.



这FormCreate()程序建立了有关「汽车车灯」的物件结构表﹕





p1:=aly2.GetChild(0)取出「灯泡」小物件﹐并由p1指向这个小物件。p2:=p1.GetChild() 取出「灯帽」小物件﹐并由p2指向之。依上述之样式﹐可表达出无限层次的递回式Whole-part关系。



结语

为了让软体能永续生存下去﹐必须特别重视软体的组织与其整体架构(architecture)。于是﹐必须专注于物件之间的互助合作关系。一旦建立了理想的关系﹐就可以让物件之间互相传递讯息、互相沟通了。例如﹐Form1 物件传送Cost讯息给aly2物件﹐aly2物件就依循TList 物件所建立的关系(透过指标)来将Cost讯息递给内含之各小物件。当各小物件回报其成本金额﹐aly2将之累计再传送回到Form1 物件﹐然后显示在视窗画面上。阅读本文之后﹐相信您会进一步了解Whole-part关系﹐也会更加活用容器类别来表达之。同时也希望您更会运用样式来创造出更美好的软体。■

[注1] Erich Gamma,Design Patterns: Elements of Reusable Object-Oriented Software, Addition-Wesley, 1995.

 
看看帮助吧!
 
后退
顶部