DelphiScript
Phần này mô tả ngôn ngữ DelphiScript được Scripting Engine của Altium Designer sử dụng, đồng thời cung cấp thông tin tham khảo chi tiết về các câu lệnh, hàm và phần mở rộng được hỗ trợ. Đây là các thủ tục đặc biệt dùng để điều khiển và giao tiếp trực tiếp với Altium Designer.
Ngoài ra, trong tài liệu tham khảo này còn có:
- Sự khác biệt giữa DelphiScript và Delphi
- Từ khóa DelphiScript
- Câu lệnh và toán tử DelphiScript
- Hàm DelphiScript
- Biểu mẫu và thành phần DelphiScript
Ngôn ngữ DelphiScript
Tài liệu tham khảo DelphiScript này giả định rằng bạn đã quen với các khái niệm lập trình cơ bản cũng như cách vận hành cơ bản của Altium Designer. Hệ thống scripting hỗ trợ ngôn ngữ DelphiScript, vốn rất giống với Embarcadero Delphi™.
Điểm khác biệt chính là DelphiScript là một ngôn ngữ scripting không kiểu hoặc không định kiểu, nghĩa là bạn không thể định nghĩa record hoặc class và truyền con trỏ làm tham số cho hàm. Tuy vậy, biến vẫn có thể được khai báo trong script để tăng tính dễ đọc.
Trang này và các trang con đi kèm chứa tài liệu tham khảo về interface, component, routine toàn cục, kiểu dữ liệu và biến tạo nên ngôn ngữ scripting DelphiScript.
Các thành phần chính của Delphiscript
Đối tượng
Trong DelphiScript, một Object bao gồm các method, và trong nhiều trường hợp, cả property và event. Property biểu diễn dữ liệu chứa trong đối tượng, Method là các hành động mà đối tượng có thể thực hiện, còn Event là các điều kiện mà Object có thể phản ứng. Tất cả Object đều kế thừa (inherit) từ đối tượng cấp cao nhất của kiểu TObject.
Interface đối tượng
Một Object Interface bao gồm các method, và trong nhiều trường hợp cả property, nhưng không thể có trường dữ liệu. Một Interface biểu diễn một Object đã tồn tại, và mỗi Interface có một GUID để định danh duy nhất. Property biểu diễn dữ liệu chứa trong Object mà Interface đó liên kết tới. Method là các hành động mà Object (mà interface liên kết tới) có thể thực hiện.
Thành phần
Component là các đối tượng trực quan từ bảng Tool Palette có thể được thao tác trong quá trình thiết kế. Tất cả Component đều kế thừa từ lớp hệ thống TComponent trong Visual Component Library (VCL) của Embarcadero Delphi.
Routine
Routine toàn cục là các Procedure và Function của hệ thống scripting. Các Routine này không thuộc về một class nhưng có thể được gọi trực tiếp hoặc từ bên trong các method của class trong một script.
Kiểu dữ liệu
Các kiểu biến được dùng làm kiểu trả về và kiểu tham số cho method và property của Interface, method, property và event của object, cũng như các routine toàn cục. Trong nhiều trường hợp, các Type được mô tả trong các phần Enumerated Types của tài liệu API.
Altium Designer và Delphi RTL
Hệ thống scripting hỗ trợ một tập con của Embarcadero Delphi Run Time Library (RTL) và API của Altium Designer.
Tệp nguồn DelphiScript
Trong Altium Designer, một dự án script được tổ chức để lưu trữ các tài liệu script (script Unit và script Form). Bạn có thể thực thi script từ một mục menu, nút trên thanh công cụ hoặc từ hộp thoại Select Item To Run có trong menu chính của Altium Designer.
Tệp PRJSCR, PAS và DFM
Các script được tổ chức thành các dự án với phần mở rộng *.PRJSCR. Mỗi dự án bao gồm các tệp có phần mở rộng *.pas. Tệp có thể là script Unit hoặc script Form — lưu ý rằng mỗi Form có một tệp script với phần mở rộng *.pas và một tệp Form tương ứng với phần mở rộng *.dfm. Một script Form là một cửa sổ đồ họa (hộp thoại) chạy bên trên Altium Designer và chứa các điều khiển khác nhau mà người dùng có thể truy cập.
Có thể gắn script vào các dự án khác nhau, và rất nên tổ chức script thành các dự án riêng để quản lý số lượng script cũng như các procedure/function của chúng.
Script ví dụ
Bộ sưu tập script ví dụ minh họa các tính năng cơ bản của lập trình DelphiScript bằng các script đơn giản để sử dụng trong Altium Designer.
Vị trí và mục đích của một số script ví dụ được liệt kê dưới đây:
Scripts\DelphiScript Scripts\DXPthư mục - Minh họa Client và system APIScripts\DelphiScript Scripts\PCB thư mục - Minh họa PCB APIScripts\DelphiScript Scripts\Processesthư mục - Minh họa các Process của serverScripts\DelphiScript Scripts\Generalthư mục - Minh họa các từ khóa DelphiScriptScripts\DelphiScript Scripts\Schthư mục - Minh họa Schematic APIScripts\DelphiScript Scripts\WSMthư mục - Minh họa Workspace Manager API
Viết script DelphiScript
Quy ước đặt tên trong DelphiScript
Nhìn chung, không có hạn chế nào đối với tên được đặt cho procedure, function, biến và hằng, miễn là chúng tuân theo các quy tắc sau:
- Tên có thể chứa các chữ cái A đến Z, a đến z, ký tự gạch dưới "_" và các chữ số từ 0 đến 9.
- Tên phải bắt đầu bằng một chữ cái.
- Tên không được là từ khóa DelphiScript, chỉ thị hoặc từ dành riêng.
- Khi được thông dịch, tên không phân biệt chữ hoa chữ thường. Có thể dùng cả chữ hoa lẫn chữ thường khi đặt tên cho function, subroutine, biến hoặc hằng; tuy nhiên, bộ thông dịch sẽ không phân biệt chữ hoa và chữ thường. Những tên chỉ khác nhau về chữ hoa/chữ thường sẽ được DelphiScript coi là cùng một tên.
Trong một tệp DelphiScript, function và procedure được khai báo bằng các khối Procedure-Begin-End hoặc Function-Begin-End. Cả hai khối câu lệnh này đều yêu cầu một tên cho procedure hoặc function. DelphiScript cho phép bạn tạo các biến và hằng có tên để lưu các giá trị dùng trong script hiện tại.
Thêm chú thích
Trong script, chú thích là các dòng mã không được thực thi, được thêm vào để hỗ trợ lập trình viên. Chú thích có thể được chèn gần như ở bất kỳ đâu trong script.
Mọi văn bản theo sau // hoặc được đặt trong (* *) hoặc {} sẽ bị DelphiScript bỏ qua.
//This whole line is a comment
{This whole line is a comment}
{
These lines are comments
These lines are comments
}
(* This whole line is a comment *)
(*
These lines are comments
These lines are comments
*)
Chú thích cũng có thể được đặt trên cùng một dòng với mã thực thi. Ví dụ, mọi thứ sau dấu chấm phẩy trong dòng mã sau sẽ được xem là chú thích.
ShowMessage ('Hello World'); //Display Message
Biến cục bộ và biến toàn cục
Vì tất cả script đều có biến cục bộ và biến toàn cục, nên việc có tên biến duy nhất trong các script thuộc cùng một dự án script là rất quan trọng. Nếu biến được định nghĩa outside bất kỳ procedure và function nào, thì chúng là biến toàn cục và có thể được truy cập bởi bất kỳ script unit nào trong cùng dự án.
Nếu biến được định nghĩa inside một procedure hoặc function, thì các biến cục bộ này sẽ không thể truy cập từ bên ngoài các procedure/function đó.
Example of Local and Global Variables in a Script:
// Note: The Uses keyword is not needed.
{ The global variable from UnitA script (see below) is available to this Script Unit,
as long UnitA is in the same project as this Script Unit. }
Const
GlobalVariableFromThisUnit='Global Variable from this unit';
Procedure TestLocal;
var
Local;
Begin
Local := 'Local Variable';
ShowMessage(Local);
End;
Procedure TestGlobal;
Begin
//ShowMessage(Local); // This line produces an error because the 'Local' variable is not global.
ShowMessage(GlobalVariableFromThisUnit);
// A variable from UnitA can be accessed without the Uses keyword.
ShowMessage(GlobalVariableFromUnitA);
End;
UnitA script:
Const
GlobalVariableFromUnitA = 'Global Variable from Unit A';
Sử dụng biến có tên
Trong script, biến hoặc hằng có tên được tạo ra để lưu trữ các giá trị sẽ được sử dụng trong quá trình thực thi chương trình. Tất cả biến trong script luôn có kiểu Variant. Việc ép kiểu không được áp dụng, vì vậy các Type trong khai báo biến sẽ bị bỏ qua và có thể không cần ghi. Do đó, các khai báo sau là đúng:
Var a : integer;
Var b : integer;
Var c, d;
Ngắt dòng
Mỗi câu lệnh mã kết thúc bằng ký tự ; dấu chấm phẩy để chỉ ra điểm kết thúc câu lệnh. DelphiScript cho phép bạn viết một câu lệnh trên nhiều dòng mã, tách một chỉ thị dài thành hai hoặc nhiều dòng. Hạn chế duy nhất khi tách câu lệnh lập trình thành nhiều dòng là chuỗi literal không được trải dài qua nhiều dòng.
For example:
X.AddPoint( 25, 100);
X.AddPoint( 0, 75);
// is equivalent to:
X.AddPoint( 25, 100); X.AddPoint( 0, 75);
however...
'Hello World!'
\\is not equivalent to
'Hello
World!'
DelphiScript không áp đặt giới hạn thực tế nào lên độ dài của một dòng mã đơn trong script, nhưng để dễ đọc và dễ gỡ lỗi, nên giữ độ dài dòng mã ở mức có thể dễ dàng đọc được trên màn hình hoặc khi in ra.
Nếu một dòng mã quá dài, bạn có thể tách dòng đó thành nhiều dòng, và bộ thông dịch DelphiScript sẽ xử lý đoạn mã này như thể nó được viết trên một dòng duy nhất.
Unformatted code example:
If Not (PcbApi_ChooseRectangleByCorners(BoardHandle,'Choose first corner','Choose final corner',x1,y1,x2,y2)) Then Exit;
Formatted code example:
If Not (PcbApi_ChooseRectangleByCorners(BoardHandle,
'Choose first corner',
'Choose final corner',
x1,y1,x2,y2)) Then Exit;
Phân biệt chữ hoa chữ thường
Ngôn ngữ DelphiScript dùng để viết script không phân biệt chữ hoa chữ thường — nghĩa là mọi từ khóa, câu lệnh, tên biến, tên function và procedure đều có thể được viết mà không cần quan tâm đến việc dùng chữ hoa hay chữ thường. Chữ hoa và chữ thường được xem là tương đương.
Ví dụ, tên biến myVar tương đương với myvar và MYVAR. DelphiScript coi tất cả các tên này là cùng một biến.
Ngoại lệ duy nhất là trong các chuỗi literal, chẳng hạn như chuỗi tiêu đề của định nghĩa hộp thoại hoặc giá trị của một biến chuỗi. Các chuỗi này vẫn giữ nguyên khác biệt về chữ hoa/chữ thường.
Ký tự khoảng trắng
Dấu cách được dùng để tách các từ khóa trong một câu lệnh script. Tuy nhiên, DelphiScript sẽ bỏ qua mọi khoảng trắng thừa trong câu lệnh.
Ví dụ:
X = 5
// is equivalent to
X =5
Bạn có thể dùng khoảng trắng để làm cho script dễ đọc hơn.
Function và Procedure trong script
Bộ thông dịch DelphiScript cho phép hai loại method (procedure): Procedure và Function. Khác biệt duy nhất giữa function và procedure là function trả về một giá trị.
Một script có thể có ít nhất một procedure định nghĩa mã chương trình chính. Tuy nhiên, bạn cũng có thể định nghĩa các procedure và function khác để được gọi từ mã của mình.
Tương tự như trong Embarcadero Delphi, procedure và function được định nghĩa bên trong một khối câu lệnh Begin-End. Để gọi một function hoặc procedure, hãy đưa tên của function hoặc procedure vào một câu lệnh theo cách tương tự như khi dùng các function và procedure DelphiScript dựng sẵn. Nếu function hoặc procedure yêu cầu tham số, thì các tham số này phải được đưa vào câu lệnh gọi. Cả function và procedure đều có thể được định nghĩa để nhận tham số, nhưng chỉ function mới có thể được định nghĩa để trả về một giá trị cho câu lệnh gọi.
Khi được định nghĩa, function và procedure có thể được đặt bất kỳ tên nào, miễn là tên đó tuân theo các quy ước đặt tên chuẩn của DelphiScript.
Typical DelphiScript Procedure:
Procedure CreateSchObjects;
Begin
If SchServer = Nil Then Exit;
SchDoc := SchServer.GetCurrentSchDocument;
If SchDoc = Nil Then Exit;
PlaceSchematicObjects;
SchDoc.GraphicallyInvalidate;
End;
Typical DelphiScript Function:
Function BooleanToString(AValue : Boolean) : String;
Begin
If (AValue) Then Result := 'True'
Else Result := 'False';
End;
Không thể dùng tên của một hàm để thiết lập giá trị trả về của nó. Thay vào đó phải dùng từ khóa Result.
Var, Begin-End global block:
Var
A, B, C;
Begin
B := 10;
C := 20;
A := B + C;
ShowMessage(IntToStr(A));
End;
Mẹo Scripting
Tham chiếu Script trong một Dự án Script
Mã trong một script có thể gọi một thủ tục trong script khác thuộc cùng dự án script. Mọi biến toàn cục trong bất kỳ script nào đều có thể được truy cập trong cùng một dự án.
Biến Cục bộ và Biến Toàn cục
Vì script có cả biến cục bộ và biến toàn cục, nên điều quan trọng là phải dùng tên biến duy nhất trong các script thuộc một dự án script. Nếu biến được định nghĩa bên ngoài mọi thủ tục và hàm, thì chúng là biến toàn cục và có thể được truy cập bởi bất kỳ unit nào trong cùng dự án. Nếu biến được định nghĩa bên trong một thủ tục hoặc hàm, thì các biến cục bộ này sẽ không thể truy cập từ bên ngoài các thủ tục/hàm đó.
Khuyến nghị đưa các script có tính chất tương tự vào cùng một dự án và giữ số lượng script trong một dự án ở mức dễ quản lý — việc theo dõi các biến toàn cục trong nhiều script có thể trở thành vấn đề. Không bắt buộc phải lưu script trong một dự án script, vì script cũng có thể được đặt trong các loại dự án khác.
Định danh và Biến Duy nhất
Khi sử dụng biểu mẫu script, hãy đảm bảo rằng tất cả biểu mẫu script đều có tên biểu mẫu duy nhất. Có thể xảy ra trường hợp tất cả biểu mẫu script đều được đặt tên là form1 (ví dụ) trong cùng một dự án script. Trong trường hợp này, hệ thống scripting sẽ bị xung đột khi cố gắng hiển thị đúng biểu mẫu lúc một biểu mẫu script được chạy.
Tên biểu mẫu script có thể được thay đổi bằng cách dùng Object Inspector. Tên sẽ tự động được thay đổi trong cả tệp script unit và tệp biểu mẫu script.
Thủ tục và Hàm không có tham số
Script nên được viết sao cho các thủ tục cần được gọi để chạy script sẽ chỉ xuất hiện trong hộp thoại Select Items to Run. Để ngăn các thủ tục/hàm khác xuất hiện trong hộp thoại Select Items to Run, có thể chèn tham số (Dummy : Integer) bên cạnh tên phương thức. Xem ví dụ bên dưới.
// This function is prevented from appearing in the Select Items to Run dialog.
Function TSineWaveform.CreateShape(Dummy : Integer);
Begin
//Do something
End;
{..................................................}
{..................................................}
Procedure TSineWaveform.bCloseClick(Sender: TObject);
var
I : integer;
Begin
//Doing something
Close;
End;
{..................................................}
{..................................................}
procedure DrawSine;
Begin
SineWaveform.showmodal;
End;
Mã lỗi DelphiScript
|
Error |
Description |
|---|---|
|
|
Chuỗi được dùng trong script không đúng. |
|
|
Chuỗi được dùng trong script không đúng. |
|
|
Không cho phép có nhiều hàm trùng tên trong mã. Hãy đổi tên các hàm khác có cùng tên. |
|
|
Định danh không xác định. Cần khai báo định danh này trước khi sử dụng. |
|
|
Script có kiểu Biến không hợp lệ hoặc không xác định. |
|
|
Không cho phép có nhiều unit trùng tên. Hãy đảm bảo tên script unit là duy nhất. |
|
|
Khai báo unit không được định nghĩa đúng cách. |
|
|
Thiếu hàm trong script. |
|
|
DelphiScript không thể liên kết script với các thành phần nội bộ cần thiết. |
|
|
Có nhiều nhãn trùng nhau trong script. Hãy đảm bảo các nhãn là duy nhất trong script. |
|
|
Khối khai báo không được định nghĩa đúng cách. |
|
|
Nhãn Goto chưa được định nghĩa. |
|
|
Có nhiều biến trùng nhau trong script. Hãy đảm bảo các biến là duy nhất. |
|
|
Có lỗi trong khối khai báo biến. Khai báo sai hoặc các khai báo không được hệ thống scripting nhận diện. |
|
|
Biến chưa được định nghĩa, vì vậy hệ thống scripting không thể xác định biến này. |
|
|
Chữ ký phương thức không hợp lệ. |
|
|
Tham số dùng cho phương thức không đúng. |
|
|
Các thuộc tính của đối tượng không được hệ thống scripting nhận diện. |
|
|
Đã cố gắng khai báo các kiểu khai báo ngoài class. |
|
|
Có lỗi khai báo trong script. |
|
|
Đã xảy ra lỗi cú pháp trong script |
|
|
Tên định danh không hợp lệ, chẳng hạn như tên định danh bị trùng lặp. Hãy định nghĩa lại tên định danh. |
|
|
Định danh không hợp lệ. Hãy định nghĩa một định danh mới |
|
|
Hàm không được dùng đúng cách trong script |
|
|
Thủ tục không được dùng đúng cách trong script |
|
|
Giá trị hằng số hex không được khai báo đúng cách. |
|
|
Script cần được biên dịch trước khi có thể chạy. Đây là lỗi nội bộ. |
|
|
Lỗi khai báo hằng số kiểu Real. |
|
|
Lỗi khai báo hằng số kiểu String. |
|
|
Kiểu tham số không xác định theo báo cáo của hệ thống scripting. |
|
|
Không tìm thấy giá trị kết quả của biến cho chuỗi đã chỉ định trong script. |
|
|
Thiếu thủ tục trong script. |
|
|
Thiếu tham số trong script. |
|
|
Lỗi nội bộ. |
|
|
Cùng một thủ tục hoặc hàm được khai báo và triển khai khác nhau. Hãy kiểm tra các tham số giữa hai phần này. |
|
|
Một trong các tham số của phương thức, hàm hoặc thủ tục không có kiểu variant đúng. |
|
|
Đã cố gắng thiết lập giá trị cho thuộc tính chỉ đọc hoặc thuộc tính đó không tồn tại. |
|
|
Các đối số dùng cho thủ tục hoặc hàm không hợp lệ đối với script. |
|
|
Thiếu giá trị tham số. |
|
|
Dùng sai kiểu tham số. |
|
|
Giao diện này chưa được khai báo hoặc định nghĩa. |
|
|
Thiếu tham số bắt buộc cho phương thức, hàm hoặc thủ tục. |
|
|
DelphiScript đã phát hiện một lỗi script không xác định, không được định nghĩa trong bảng lỗi nội bộ. |
|
|
DelphiScript đã phát hiện một mã thao tác không hợp lệ. |