PasScript基础
# PasScript基础
# 1. 简介
PasScript 是一个脚本库。 对于想要为他们的项目添加脚本能力的程序员来说,它很有用。 目前Flying,FastERP以及Smart中集成的FastReport模块,以及FastWeb的脚本引擎均使用了PasScript。
PasScript 的独特之处在于填写脚本后,无需进行编译等操作就可以直接执行。因此您无需编写额外的程序代码即可执行它。PasScript 结合了跨平台脚本、快速代码执行、占用空间小、丰富的功能集和出色的可扩展性。 使用 PasScript 使您的应用程序成为最灵活、最强大的应用程序!
# 2. 快速开始
以下示例代码演示了使用PasScript最简单的方式。请使用PasScript驱动的程序(比如FastReport)来进行测试。打开报表设计器,切换至代码
选项卡,按照下述的代码进行填写:
begin
ShowMessage('Hello!');
end.
2
3
没错,正如你所看到的,以上语法再简单不过,脚本内容可以使用你最熟悉的语法来编写,如果语法没有错误,则执行预览运行后你可以得到一个如下图的提示消息窗口。
# 3. 语法特点
PasScript与其他的Pascal语言语法相比,有新的特性,也缺少一些特征。
# 3.1. 具有的特性
- 标准语法:支持变量,常量,过程和函数(嵌套函数)定义,同时允许程序和函数参数列表中使用
var
、const
、default value
等参数类型,支持Pascal几乎所有的标准操作符,支持标准语句包括case
、try
、with
等,支持数据类型包括Integer
、Real
、Double
、TDate
、TTime
、TDateTime
、Boolean
、Char
、String
、Array
、Enum
、Variant
等,支持Pascal中的大多数标准组件与类,包括这些组件的方法、事件、属性。 - 类型兼容性检查,例如
Double
能够兼容Real
和Integer
- 能够访问程序中的任何对象,也很容易扩展来自于Pascal的标准库的组件和类。
- 代码一般小于90-150KB。
- 支持多线程环境。
# 3.2. 不具有的特性
- 无类型定义,不能在脚本中声明自己的记录类型和新类,在PasScript中,没有记录型,没有指针,没有集合,没有标准字符串(均为宽字符串,也就是一个中文只是一个字符),没有
GOTO
语句。 - 无动态数组定义,不能定义长度未知的数组。
# 4. 基本数据类型
PasScript具有以下基本数据类型,但是在编译后,对应的数据类型相对较少。

# 5. 基本语法结构
PasScript的基本语法结构如下:

# 5.1. 单元引用
单元引用使用uses
关键字,每一个单元使用与当前单元的相对路径,而且不能循环引用,被引用的单元要使用编译后的扩展名,并用单引号引起来。
例如,我们在设计的时候,有一个单元文件名为Unit2.pas
,而我们要引用这个单元,则需要使用 Unit2.rpas
来进行引用,因为单元在编译后,产生的中间文件扩展名为.rpas
,另外,设计期在引用单元前一定要对被引用单元进行编译,编译方式是将被引用单元切换为活动单元文件,点击执行按钮,即会对其进行设计期编译,运行期的编译不用用户手工操作,通过编译工具会自动完成对源码列表中的文件进行编译。
# 5.2. 变量定义
变量与全局变量均使用var
开头,变量在使用前必须声明,声明变量时必须指定一种数据类型。下面是变量声明的例子:
var
Value: Integer;
IsCorrect: Boolean;
A, B: Char;
2
3
4
- 关键字
var
可以在许多地方使用,放在函数或程序的开始部分,用来声明函数或程序的局部变量。也可以放在脚本的开头,用于声明全局变量。 var
关键字之后是一组变量名列表,每个变量名后跟一个冒号和数据类型名,一行中可以声明多个变量,如上例中最后一句。- 一旦变量的类型被指定,你只能对变量执行该变量类型支持的操作。例如,在判断操作中用布尔值,在数字表达式中用整型值,你不能将布尔值和整型值混用。
对象的实例同样也可以在var
处进行定义。
var
button: TButton;
2
# 5.3. 常量定义
常量定义以const
关键字开头来定义,常量定义的时候,名称尽可能遵循大写,而且每个单词间以下划线_
连接的方式来定义,这样子使得我们的代码易读,看到这种格式的标识符的时候,我们就能够很容易理解它是一个常量。常量在定义的时候一定要赋予一个值,我们通常不指定常量的数据类型,但是也可以强制指定常量的数据类型。
常量定义语句示例:
const
WM_CLOSE = $0000010;
USER_NAME_COL : Integer = 3;
2
3
# 5.4. 数组定义语句
在编程中,数组是经常会用到的一种复杂数据类型,通常用于有序存放相同数据类型的多项数据。PasScript中的数组语句定义与Pascal类似,需要同时指定数组的下界与上界,唯一不同的,就是不支持动态设置数组的长度。
数组定义语句示例:
//一维数组
Persons : array[1..24] of string;
//二维及多维数组
Groups : array[1..20, 1..24] of string;
2
3
4
# 5.5. 赋值语句
PasScript的赋值语句与Pascal一样,使用:=
作为赋值符。
var
i: Integer;
begin
i := 0;
end;
2
3
4
5
# 5.6. 判断语句
判断语句使用if 逻辑表达式 then
与else
相配合来完成各种判断,但是如果存在多个条件表达多的时候,就需要根据情况不同,用and
或or
及()
将
多个逻辑表达式组合起来表达一个完整的意思,PasScript与Pascal一样,逻辑运算符的优先级低于判断运算符,因此需要将每一个逻辑表达式在连接之前用()
引起来,这一点也是与其它语言很大的不同之处。
对if-then型语句, 仅当条件满足时,语句才执行;
判断语句示例:
if (A<B) and (not this.FileExists(‘C:\Person.Info’)) then
begin
//此处填写要执行的PasScript语句
end;
2
3
4
人们往往在不熟悉语法的时候,会将以上语句错误地写成如下的样式:
if A<B and not this.FileExists(‘C:\Person.Info’) then
begin
...
end;
2
3
4
判断语句还有以下两种显示方式:
if - then - else
类型
//注意的是,不能在第一句之后、else 关键词之前加分号
//否则编译器将告知语法错误
//实际上,if-then-else 语句是单纯的一条语句,因此不能在语句中间加分号
if (A<B) and (not this.FileExists(‘C:\Person.Info’)) then
begin
//此处填写要执行的PasScript语句
end
else
begin
//此处填写要执行的PasScript语句
end;
2
3
4
5
6
7
8
9
10
11
if - then - else if then - else
类型
if (A<B) and (not this.FileExists(‘C:\Person.Info’)) then
begin
//此处填写要执行的PasScript语句
end
else if (A>B) and (not this.FileExists(‘C:\Person.Info’)) then
begin
//此处填写要执行的PasScript语句
end
else
begin
//此处填写要执行的PasScript语句
end;
2
3
4
5
6
7
8
9
10
11
12
# 5.7. 循环语句
循环语句是所有语言中很重要的一种语句,在PasScript中,支持三种类型的循环语句,即for
、while
、repeat
三种,for
与while
最为常见,for
需要一个循环变量来计算循环次数,在循环过程中,循环变量不可以再改变,而且步长也只能是1,但是允许通过关键字to
和downto
来控制是正向循环还是逆向循环。
for
正向循环语句示例:
for I := 0 to list.Count - 1 do
begin
//此处填写要执行的PasScript语句
end;
2
3
4
for
逆向循环语句示例:
for I := List.Count – 1 downto 0 do
begin
end;
2
3
4
while
循环语句示例:
while not Query.Eof do
begin
Query.Next;
end;
2
3
4
# 5.8. 异常捕捉语句
在PasScript中,支持异常处理语句,但是不支持通过on
来捕获错误信息的内容。异常捕捉语句的两种写法:
except
语句示例
try
except
end;
2
3
4
在FastWeb中,支持使用ExceptionMessage
来获取错误信息。
try
Except{ExceptionMessage}
vRAISEMSG:=ExceptionMessage;
...
end;
2
3
4
5
6
finally
语句示例:
try
finally
end;
2
3
4
# 5.9. 条件分支语句
在PasScript中,同样拥有和Pascal一样的条件分支语句,即case
语句,在PasScript中的case
语句比Pascal的语法更加强大和灵活,Pascal中只能使用可枚举类型作为分支条件表达式,在PasScript中还允许使用字符串作为分支条件表达式。
case
语句示例:
case WeekDay of
1:
2:
else
end;
2
3
4
5
6
# 5.10. with省略语句
同Pascal一样,PasScript同样允许使用with来简略语句写法,具体写法参考下面的示例:
with
省略语句示例:
With TStringList.Create do
begin
Add(‘Test1’);
Add(‘Chun2’);
Add(‘Dang-001’);
Sort;
ShowMessage(Text);
Free;
end
2
3
4
5
6
7
8
9
# 5.11. 程序及函数声明语句
程序与函数的声明与Pascal相同,程序与函数的区别主要在于是否具有返回值,程序没有返回值,函数必须有返回值。
- 程序与函数定义示例:
function GetUserInfo( UserId: string ): string;
procedure DeleteLeafNodeFromTree( ATreeNode: TTreeNode );
function SplitDate ( ADateTime: TDate; var Year,Month,Day: Integer): Boolean;
procedure GetTemplateFile(var TemplateFile: string);
function PickADate(ADate: string = ‘2014-12-25’) : string;
2
3
4
5
# 6. 基本运算符
PasScript的基本运算符主要分为算术运算符、条件运算符,逻辑运算符、位运算符和字符串运算符。
- 算术运算符:
+
,-
,*
,/
,mod
,div
- 条件运算符:
>
,<
,=
,>=
,<=
,<>
,in
,is
- 逻辑运算符:
and
,or
,not
- 位运算符:
shr
,shl
,and
,not
,or
,xor
- 字符运算符:
+
# 7. 枚举与集合
PasScript虽然不支持集合定义,但是通过另外的方式对集合进行了支持,例如在Pascal中字体风格就是一个枚举集合类型,下面将两种方式进行了对比:
Pascal中的代码:
Font.Style := [fsBold];
Font.Style := [fsBold, fsItalic];
Font.Style := [];
2
3
PasScript中的代码:
Font.Style := fsBold;
Font.Style := fsBold + fsItalic;
Font.Style := 0
2
3
# 8. 高级说明
在了解并使用PasScript之前,您应该要对以下的一些基础概念有所了解。这样对脚本的编写有更大的帮助。
# 8.1. 面向对象
面向对象编程是最近几年很火的概念,甚至都已经立足了神坛。
面向对象是一种解决问题的思路而不是一个具体的东西。面向对象是在解决问题时的粒度和思维方式发生了变化,相比以前(面向过程)粒度更大。
虽然面向对象不能使得代码容易编写,但是它能够使得代码易于维护。将数据和代码结合在一起,能够使定位和修复错误的工作简单化,并最大限度地减少对其他对象的影响,提高代码的性能。
面向对象相关的三个术语:
- 域(field),也被称为域定义或者实例变量,域是包含在对象中的数据变量。在C++中它被称为数据成员。通常不会直接去访问域相关的内容。
- 方法(method),属于一个对象的过程和函数名,在C++中它被称为成员函数。
- 属性(property),属性是外部代码访问对象中的数据和代码的访问器,属性隐藏了一个对象的具体实现的细节。
PasScript是完全的面向对象的环境,这表示在PasScript中你能用已经存在的组件创建新的对象,这些对象是可视的或者不可视的,甚至可以是设计时的窗体。
在PasScript中,通常需要使用一个对象的变量,即实例。实例定义在var部分。
var
FButton: TButton;
2
通过调用它的一个构造器来建立一个对象的实例,构造器主要是用来为对象创建实例并为对象中的域分配内存进行初始化使得对象处于可使用的状态。通过调用构造器来创建对象的实例,这就是所谓的实例化。通常使用Create
来进行构造。
FButton := TButton.Create(nil);
注意是通过类型来引用一个对象的Create()
方法,而不是像其他方法那样通过实例来引用。通过调用构造器来创建对象的实例,这就是所谓的实例化。
当用完对象,应该调用这个实例的Free()
方法来释放它。Free()
首选进行检查保证这个对象实例不为NIL,然后调用对象的析构方法Destroy()
。
FButton.Free;
析构进行与构造相反的工作,它释放所有分配的空间,并执行一些其他操作以保证对象能够适当地移除内存。
不像调用Create()
,这里是调用对象实例的Free()
方法,记住不要直接调用Destroy()
,而调用更安全的Free()
方法,因为Free()
首选进行检查保证这个对象实例不为NIL,然后调用对象的析构方法Destroy()
。
所有使用Create()
动态声明创建的对象即使离开创建它时候的作用域,它也不会被自动释放,必须使用Free()
方法来动态的析构,除了在PasScript中的隐式动态创建的对象,所以一定要记住这个规则:凡是创建的,都需要释放。这个规则有以下重要的特例:
- 当对象被其他对象拥有时,它将替你释放对象。
- 引用技术的对象,当最后一个引用释放时,它将被析构。
- 手动创建的控件同时指定它的父容器,此时的释放由父容器完成。
# 8.2. 组件
组件也是一种特殊的对象,它在PasScript中运用广泛,我们在FastWeb或者FastReport中使用的几乎全部都是这种类型的对象。其可分为两大类:控件和非可视组件。
- 控件:所有的控件均派生于
TControl
类,控件在屏幕上有位置与大小,并且设计时在窗体中显示的位置与运行时相同。控件有两种不同的子规格,基于窗口或图形化。 - 非可视组件:所有非可视组件都不是控件,在设计时,非可视使组件在窗体上显示为一个图标,在运行时,其中有些组件可以显示(比如执行时会产生对话框的组件),有些不能显示(数据连接相关的控件)。
# 8.2.1. 如何使用组件
以FastWeb使用的PasScript为例,组件的使用有以下两种方式。
在窗口设计器中引入。参照FastWeb快速上手中的说明进入至设计页面,可以看到页面设计区域的上方有包含可以选择的控件页面,带有名称的标签为组件的分组名称,点击标签切换进入至对应的分组中。

鼠标移动至每个组件的图标上,可显示每个组件对应的类的名称,单击图标以选择此组件,选择组建后,在设计区的页面上单击,组件会被放置到设计页面上。通过这种方式,组件被引入至设计区中,可以使用脚本来引用组件的属性与方法。
比如,我们在标准
选项卡中单击选择第二个组件TUgButton
,然后在设计区单击,将组件放置在设计区,放置后的页面显示如下:

从脚本中引入。如果需要通过脚本来动态创建并使用组件的,可以按照组件中描述的方式来创建组件。比如可以在程序中临时创建,在程序结束后销毁:
//保存
procedure btnSaveOnClick(sender: tobject);
Var
//声明对象组件
vdts: TUgRFDataSet;
begin
//创建对象组件
vdts := TUgRFDataSet.Create(Nil);
vdts.Connection := GetRFERP;
try
//其他的脚本信息
...
Finally
//程序结束时销毁组件
vdts.Free;
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
关于FastWeb的其他组件的相关信息可以参考 FastWeb参考手册之控件使用。
# 8.3. 属性
属性是一种非常有效的面向对象机制,或者说非常适合实现封装的思想。从本质上讲,属性就是用一个名称来完全隐藏它的实现细节。属性就是一个虚拟字段,从定义它们的类的角度来看,属性就像字段一样,因为用户可以读取或编写它们的值。例如,可以用下列代码读取一个按钮的Caption
属性值,并将其赋给一个带有下列代码的编辑框的Text
属性:
Edit1.Text := Button1.Caption;
这看起来像是在读写字段一样,然而,属性可以直接与数据以及访问对象的方法对应起来,用于读写数值。
# 8.3.1. 使用属性
以FastWeb使用的PasScript为例,参照 FastWeb快速上手 中的说明进入至设计页面,并放置好TUgButton
组件,在设计区的页面中点击此组件,在左侧的对象查看器中可以看到此组件可见的属性与事件信息。
这些属性信息以列表的形式呈现,可以使用鼠标或者键盘来直接进行属性的修改,有些属性在使用对象查看器进行修改后可以看到修改后的效果。

比如在上述的示例中,假如我们需要修改按钮中显示的内容,则可以修改Caption
属性,将其修改为btnTest
,修改后显示如下。

也可以使用脚本来修改属性。假如需要使用脚本来修改按钮显示的文字信息,点击设计区域下方的标签,切换至脚本
页面。在Begin
与End
中间输入以下内容:
//属性在脚本中的使用
UgButton01.Caption := 'btnTest1';
2
通过脚本修改的属性在设计页面中无法及时预览到结果,需要点击左上侧的[运行]
按钮后可以看到相关的运行效果。
关于FastWeb中各组件的属性信息可以参考FastWeb参考手册之控件使用。
# 8.4. 对象方法
对象的方法使用function
或procedure
关键字来定义,这取决于它是否含有一个返回值。在脚本中,可以使用类的实例化对象名称作为前缀,并使用点号作为分隔符:
Memo.Lines.Clear;
关于方法,在PasScript中还有一些有用的特性:
- 方法可以有一个或多个带有默认值的参数,如果这些参数方法在调用时被忽略,它们将会得到默认值。
- 在一个方法中,可以使用
Self
关键字访问当前对象,当引用对象的本地数据时,对Self
的引用就是隐含的了。
# 8.4.1. 使用对象方法
对象的方法和属性一样,也是通过脚本来进行引用,假如在之前使用的示例UgButton01
,我们要使释放清除此控件,可以使用Free
方法进行。在脚本页签中,我们将原先在Begin
与End.
之间的内容清除,重新在其中输入以下内容:
UgButton01.Free;
当调用此对象的方法后,此控件会被释放。
关于FastWeb中各组件的方法详情可以参考FastWeb参考手册之控件使用。
# 8.5. 事件
组件是通过属性、对象方法与事件进行编程的,现在,我们只对对象方法与属性进行了论述,而事件的内容还没有介绍。原因是事件没有新添加语言特性。它只是一种标准的编程技术。事实上,事件从技术上讲就是属性,二者的惟一区别就是事件引用了对象的方法,而不是其他类型的数据。
当用户对组件进行一些操作时,如单击它,组件就会产生一个事件。其他事件由系统产生,如响应一个对象方法调用或修改该组件的某个属性。例如如果用户将焦点设置在一个组件上,那么当前有焦点的组件就会失去它,这样就触发了相应的事件。
# 8.5.1. 使用事件并创建程序
在上述的示例中,我们将原先的内容清除,点击界面
标签返回至设计区,点击选择UgButton01
控件,左侧的对象选择器点击事件
切换至事件列表,列表中展示了所有可以使用的事件。
假如我们需要在按钮点击操作时执行相关的脚本信息,那么可以使用OnClick
事件去设置。可以使用鼠标左键去双击OnClick
右侧的下拉文本框,页面会自动切换至脚本
标签,右侧的脚本区域多了以下几行的内容。
procedure UgButton01OnClick(sender: tobject);
begin
end;
2
3
4
以上就是通过OnClick
事件触发的程序,触发时的相关操作可以通过在begin
与end;
中间输入相关操作的脚本来实现。比如我们在其中输入以下内容:
UgButton01.Caption := 'Hello';
运行后,点击图中的btnTest
按钮,按钮中显示的内容会变成Hello
。
关于FastWeb中各组件的事件信息可以参考FastWeb参考手册之控件使用。
# 9. 在Report中使用PasScript
Report中使用PasScript可参考FastReport说明。
# 10. 在FastWeb中使用PasScript
FastWeb中需要创建模块,在模块设计界面中才可以使用PasScript。详细的操作说明可参考FastWeb开发案例以及FastWeb快速上手。