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快速上手。