Listbox1.Items.Add ('Random Number: ' + IntToStr (I)); end; end;
每次点击While按钮,出现的数字都不同,因为这些数字取决于随机数发生器。图5.3显示了两次点击的结果,可看到不仅每次产生的数字不同,而且数据项数也不同。也就是说,这个while循环执行的次数是随机的。
图 5.3: 按While按钮后显示的结果
注意:用 Break 和 Continue 系统过程可以改变循环执行的标准流程。Break 中断循环;Continue直接跳至循环测试句,或使计数器增加一个步长,然后继续循环(除非条件为空或计数器达到最大值)。还有两个系统过程 Exit 和 Halt,让你立即从函数或过程中返回,或者终止程序。 With语句
要讲的最后一种Pascal 语句是With语句,它在Delphi程序设计中很有用。
31
With语句是一种用于简化代码的语句。如你要访问一个记录类型变量(或一个对象),用With语句就不必每次重复变量的名字。例如对于以下的记录类型代码: type
Date = record Year: Integer; Month: Byte; Day: Byte; end; var
BirthDay: Date; begin
BirthDay.Year := 1997; BirthDay.Month := 2; BirthDay.Day := 14;
可以用with语句改进后半部分代码,如下: begin
with BirthDay do begin
Year := 1995; Month := 2; Day := 14; end;
在Delphi程序中,这种方法能用于访问控件和类变量。现在通过with语句访问列表框的条目,我们重写上面循环例子的最后部分:
procedure TForm1.WhileButtonClick(Sender: TObject); var
I: Integer; begin
with ListBox1.Items do begin
Clear; // shortcut Randomize; I := 0;
while I < 1000 do begin
I := I + Random (100); // shortcut:
Add ('Random Number: ' + IntToStr (I));
32
end; end; end;
当你使用控件或类时,with语句通常能简化你的代码,尤其对嵌套域。例如,你要改变窗体画笔的宽度和颜色,你可以写代码如下: Form1.Canvas.Pen.Width := 2; Form1.Canvas.Pen.Color := clRed;
但如果用With语句代码会更简单: with Form1.Canvas.Pen do begin
Width := 2; Color := clRed; end;
当编写的代码很复杂时,with语句会很有用,也可省去一些临时变量。但是这样做也有缺点,因为这样将使代码的可读性变差,特别对有相似或相同属性的对象。
更严重的是,使用with语句可能会在代码中融入微妙的逻辑错误,甚至连编译器都难以发现。例如: with Button1 do begin
Width := 200;
Caption := 'New Caption'; Color := clRed; end;
这段代码改变了按钮的Caption 和 Width属性,但也改变了窗体的Color属性,而不是按钮的颜色!其原因是 TButton 控件没有Color属性, 又由于执行的代码是针对窗体对象的(我们正在写窗体的方法),所以窗体对象即成为默认的访问对象。如果这样写: Button1.Width := 200;
Button1.Caption := 'New Caption'; Button1.Color := clRed; // error!
编译器会给出一个错误。通常,由于with语句在当前的块中定义了新的标识符,省略了原有的标识符,可能引起在同一块内错误地访问另一个标识符(就象上面的这段代码)。即使存在种种缺陷,我还是建议你习惯于使用with语句,因为with语句确实是非常便利,并且有时也会使代码更容易读懂。
然而,你应该避免使用多个with语句,如:
33
with ListBox1, Button1 do...
这样会使后面的代码非常难读,因为,对该块中定义的每个属性,你都要根据相应的属性以及控件的次序,才能推出所访问的控件。
注意:说到可读性,要知道Pascal 没有endif 或endcase 语句。如果if语句有一个begin-end 块,那么end标志语句结束;另外,case语句也总是以一个end结束。所有这些end语句,常常是一个接一个,使代码难以理解,只有通过缩排跟踪,才能追出一个end所对应的语句。解决这个问题的一个通用办法, 也是使代码更可读的办法,是在end后面加注释,如下例: if ... then ... end; // if
Pascal 过程与函数
Pascal中的例程有两种形式:过程和函数。理论上说,过程是你要求计算机执行的操作,函数是能返回值的计算。两者突出的不同点在于:函数能返回计算结果,即有一个返回值,而过程没有。两种类型的例程都可以带多个给定类型的参数。
不过实际上函数和过程差别不大,因为你可以调用函数完成一系列操作,跳过其返回值(用可选的出错代码或类似的东西代替返回值);也可以通过过程的参数传递计算结果(这种参数称为引用,下一部分会讲到)。
下例定义了一个过程、两个函数,两个函数的语法略有不同,结果是完全相同的。 procedure Hello; begin
ShowMessage ('Hello world!'); end;
function Double (Value: Integer) : Integer; begin
Double := Value * 2; end;
// or, as an alternative
function Double2 (Value: Integer) : Integer; begin
Result := Value * 2; end;
流行的做法是用Result 给函数赋返回值,而不是用函数名。
34
一旦定义了这些例程,你就可以多次调用,其中调用过程可执行操作;调用函数能计算返回值。如下:
procedure TForm1.Button1Click (Sender: TObject); begin Hello; end;
procedure TForm1.Button2Click (Sender: TObject); var
X, Y: Integer; begin
X := Double (StrToInt (Edit1.Text)); Y := Double (X);
ShowMessage (IntToStr (Y)); end;
提示:当调用一个现有的Delphi 函数、过程或任何VCL方法时,你应该记住参数的个数及其数据类型。不过,只要键入函数或过程名及左括号,Delphi 编辑器中会出现即时提示条,列出函数或过程的参数表供参考。这一特性被称为代码参数(Code Parameters) ,是代码识别技术的一部分。 引用参数
Pascal 例程的传递参数可以是值参也可以是引用参数。值参传递是缺省的参数传递方式:即将值参的拷贝压入栈中,例程使用、操纵的是栈中的拷贝值,不是原始值。
当通过引用传递参数时,没有按正常方式把参数值的拷贝压栈(避免拷贝值压栈一般能加快程序执行速度),而是直接引用参数原始值,例程中的代码也同样访问原始值,这样就能在过程或函数中改变参数的值。引用参数用关键字var 标示。
下面是利用引用传递参数的例子,引用参数用var关键字标示: procedure DoubleTheValue (var Value: Integer); begin
Value := Value * 2; end;
在这种情况下,参数既把一个值传递给过程,又把新值返回给调用过程的代码。当你执行完以下代码时: var
X: Integer; begin
35