• TMSScripter演示


     开始脚本,只需要把脚本赋值给TatCustomScripter组件的SourceCode属性,并调用Execute方法。下面是一个简单的例子:
    Scripter.SourceCode.Text:='ShowMessage(''Hello world!'');';
    Scripter.Execute;

    现在我们变得灵活一点。在窗口上放一个Tmemo组件,并把代码改为下面这样:
    Scripter.SourceCode:=Memo1.Lines;
    Scripter.Execute;

    现在你可以在程序运行的时候在Memo组件中输入脚本,并运行它了。

    在脚本中调用程序中的子程序
    如果脚本要直接调用程序中的一个或多个函数和过程,你只要使用ExecuteSubRouti方法就可以了:
    Pascal示例
    脚本:
    procedure DisplayHelloWorld;
    begin
    ShowMessage('Hello world!');
    end;

    procedure DisplayByeWorld;
    begin
    ShowMessage('Bye world!');
    end;
    代码:
    Scripter.ExecuteSubRoutine('DisplayHelloWorld');
    Scripter.ExecuteSubRoutine('DisplayByeWorld');
    上面的代码将显示“Hello word!”和“Bye world!”消息框。

    取得脚本返回的值
    如果Delphi要取得脚本中的过程或函数返回的值,使用ExecuteSubRoutine方法。见下例:
    Pascal示例
    脚本:
    function Calculate;
    begin
    result:=(10+6)/4;
    end; 

    代码:
    FunctionValue:=Scripter.ExecuteSubRoutine('Calculate');

    如果Delphi要取得脚本所返回的值。见下例:
    脚本:
    result:=(10+6)/4;

    代码:
    FunctionValue:=Scripter.Execute;

    传递参数到脚本
    如果要把Delphi变量的值传递给脚本,还是同样使用ExecuteSubRoutine方法见下例:
    Pascal示例
    脚本:
    function Double(Num);
    begin
    result:=Num*2;
    end; 

    CODE:
    FunctionValue:=Scripter.ExecuteSubRoutine('Double',5);

    FunctionValue接收到10。如果你要传递更多的变量,就要使用一个Variant数组:

    脚本:
    function MaxValue(A,B);
    begin
    if A>B then
    result:=A
    else
    result:=B;
    end;

    代码:
    FunctionValue:=Scripter.ExecuteSubRoutine('MaxValue',VarArrayOf([5,8]));

    脚本不需要参数类型,你只需要声明他们的名字就行了。

    访问Delphi对象

    注册组件
    Scripter工作室最大的特点就是能访问Delphi对象。这使你在脚本中能有很大的灵活性,比如改变Delphi对象的属性,调用对象的方法等等。

    但是,每一个Delphi对象都必须经过注册后才能在脚本中访问。例如,你要改变窗口的标题(名字是Form1),如果你试着执行下面的脚本:
    脚本:
    Form1.Caption:='New caption';

    你只会得到“Unknown identifier or variable not declared: Form1”的错误消息。要让脚本能够正常工作,必须使用AddComponent方法:

    代码:
    Scripter.AddComponent(Form1);

    现在你再执行脚本:
    Form1.Caption:='New caption';
    窗口的标题就被改变了。

    类注册结构
    脚本可以调用对象的方法和属性,但是所要调用的方法和属性必须在脚本中注册,而管理注册的关键的属性就是TatCustomScripter.Classes属

    性,这属性保存所有已注册的类(TatClass对象),它依次序保存所有已登记的属性和方法(TatClass.Methods and TatClass.Properties)。每

    种已注册的方法和属性都有一个名字和一个包装方法(Delphi写代码将句柄方法和属性)。
    当你已注册一个Form1组件在一个例子上时,脚本自动注册TForm类在Classes属性,和注册所有published属性在它内部,要访问方法和Public

    属性,你必须注册它们,参见下列例子:

    调用方法
    调用一个对象方法,你必须注册它。例如,如果你重新创建了一个名字叫Form2的窗口,并且想要调用Form2窗口的ShowModal方法,因此我们必

    须使用AddComponent方法增加窗口到脚本,然后注册ShowModal方法:
    代码:
    procedure Tform1.ShowModalProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(TCustomForm(CurrentObject).ShowModal);
    end;

    procedure TForm1.PrepareScript;
    begin
    Scripter.AddComponent(Form2);
    With Scripter.DefineClass(TCustomForm) do
    begin
    DefineMethod('ShowModal',0,tkInteger,nil,ShowModalProc);
    end;
    end;

    脚本:
    ShowResult:=Form2.ShowModal;

    这个例子有许多新概念。首先,组件增加了AddComponent方法;然后,调用DefineClass方法注册TCustomForm类。DefineClass方法自动检查TC

    ustomForm类是否已经被注册,这样你不需要测试它。
    最后,使用DefineMethod方法注册ShowModal。DefineMethod的宣告是:
    function DefineMethod(AName:string; AArgCount:integer; AResultDataType: TatTypeKind;
    AResultClass:TClass; AProc:TMachineProc; AIsClassMethod:boolean=false): TatMethod;

    AName接收“ShowModal” - 它是用于脚本的方法的名字。
    AArgCount接收0 - 数字输入意见对于那方法。(没有,ShowModal过程在这情况下)
    AResultDataType接收tkInteger -

    它是方法返回的数据类型。ShowModal返回一个整数,如果ShowModal方法不是一个函数而是一个过程,AResultDataType将会收到tkNone。
    AResultClass接收nil - 如果方法返回一个对象(不是这个情况),那么AResultClass必须包含对象类型。例如,TField。
    AProc接收ShowModalProc - 这个方法书写用户包装ShowModal工作的方法。
    最后,有ShowModalProc方法,它是一个包装工作的方法:它执行一次ShowModal调用,在这种情况下,它使用一些TatVirtualMachine类的有用

    的方法和属性。
    属性CurrentObject - 包含对象方法的实例。因此,它包含一个TCustomForm的实例。
    在这种情况下,返回值被送回TCustomForm.ShowModal方法。

    更多方法调用例子
    除了先前的例子,这一个举例说明怎么注册和调用方法所接收到的参数和返回类。
    在这个例子,FieldByName:
    脚本:
    AField:=Table1.FieldByName('CustNo');
    ShowMessage(AField.DisplayLabel);

    代码:
    procedure TForm1.FieldByNameProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(integer(TDataset(CurrentObject).FieldByName(GetInputArgAsString(0))));
    end;

    procedure TForm1.PrepareScript;
    begin
    Scripter.AddComponent(Table1);
    With Scripter.DefineClass(TDataset) do
    begin
    DefineMethod('FieldByName',1,tkClass,TField,FieldByNameProc);
    end;
    end;

    类似先前的例子,一些注释:
    - FieldByName方法是注册在TDataset类,任何TDataset后代都允许在脚本内使用FieldByName方法。如果FieldByName已注册在一个TTable类

    ,并且组件是一个TQuery,那么脚本将不认可这个方法。
    - DefineMethod调用定义了的FieldByName收到一个参数,它的返回类型是tkClass,和类返回是TField。

    在FieldByNameProc内,调用GetInputArgAsString方法是为了顺序取得输入参数。索引0表示第一个参数,为了接收2个或多个参数,使用GetIn

    putArg(1)、GetInputArg(2),等等。

    在使用ReturnOutputArg的情况下,我们需要舍弃TField返回的整数值,这必须不返回任何对象,这是因为ReturnOutputArg接收任何一个Varia

    nt类型,和对象必须舍弃整数值。

    访问非published属性
    就和方法一样,非公布的属性必须注册,其注册机制和注册方法很相似,其差别我们必须指出一个包装取得属性值和另外一个设置属性值。在

    下列例子,那个TField 类的“AsFloat”属性已登记:

    脚本:
    AField:=Table1.FieldByName('Company');
    ShowMessage(AField.Value);

    代码:
    procedure TForm1.GetFieldValueProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(TField(CurrentObject).Value);
    end;

    procedure TForm1.SetFieldValueProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    TField(CurrentObject).Value:=GetInputArg(0);
    end;

    procedure TForm1.PrepareScript;
    begin
    With Scripter.DefineClass(TField) do
    begin
    DefineProp('Value',tkVariant,GetFieldValueProc,SetFieldValueProc);
    end;
    end;

    DefineProp是调用经过一个tkVariant标志那值属性是变量类型,然后通过两个方法GetFieldValueProc和SetFieldValueProc,依次读写TField

    对象的属性值。注意在SetFieldValueProc方法是使用GetInputArg(代替GetInputArgAsString),这是因为GetInputArg返回一个变量。

    注册索引属性
    一个属性可以被索引,特别当它是一个TCollection子孙时。这适用于dataset fields, grid columns, string items,等等。TStrings对象的

    Strings属性加进其他改变到Memo内容:
    脚本:
    ShowMessage(Memo1.Lines.Strings[3]);
    Memo1.Lines.Strings[3]:=Memo1.Lines.Strings[3]+' with more text added';

    //This is a comment

    代码:
    procedure TForm1.GetStringsProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(TStrings(CurrentObject).Strings[GetArrayIndex(0)]);
    end;

    procedure TForm1.SetStringsProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    TStrings(CurrentObject).Strings[GetArrayIndex(0)]:=GetInputArgAsString(0);
    end;

    procedure TForm1.PrepareScript;
    begin
    Scripter.AddComponent(Memo1);
    With Scripter.DefineClass(TStrings) do
    begin
    DefineProp('Strings',tkString,GetStringsProc,SetStringsProc,nil,false,1);
    end;
    end;

    访问Delphi函数、变量和常量
    除了能访问Delphi对象,脚本还允许访问全局常量、全局变量、过程和函数,其访问机制和访问Delphi对象非常相似。实际上,脚本在内部认

    为过程和函数是方法,全局变量和全局常量是属性。

    注册全局常量
    注册一个常量在脚本内是一个非常简单的工作:使用AddConstant方法增加一个常量和名字在脚本内。
    代码:
    Scripter.AddConstant('MaxInt',MaxInt);
    Scripter.AddConstant('Pi',pi);
    Scripter.AddConstant('MyBirthday',EncodeDate(1992,5,30));

    脚本:
    ShowMessage('Max integer is '+IntToStr(MaxInt));
    ShowMessage('Value of pi is '+FloatToStr(pi));
    ShowMessage('I was born on '+DateToStr(MyBirthday));

    访问全局变量
    要在脚本中注册一个全局变量,你必须使用AddVariable方法,与增加全局常量相类似:传递变量名字和变量自己。另外,你也可以用增加属性

    的方法增加变量,使用一个包装方法取得变量值和设置变量值。
    代码:
    var
    MyVar: Variant;
    ZipCode: string[15];

    procedure TForm1.GetZipCodeProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(ZipCode);
    end;

    procedure TForm1.SetZipCodeProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ZipCode:=GetInputArgAsString(0);
    end;

    procedure TForm1.PrepareScript;
    begin
    Scripter.AddVariable('ShortDateFormat',ShortDateFormat);
    Scripter.AddVariable('MyVar',MyVar);
    Scripter.DefineProp('ZipCode',tkString,GetZipCodeProc,SetZipCodeProc);
    Scripter.AddObject('Application',Application);
    end;

    procedure TForm1.Run1Click(Sender: TObject);
    begin
    PrepareScript;
    MyVar:='Old value';
    ZipCode:='987654321';
    Application.Tag:=10;
    Scripter.SourceCode:=Memo1.Lines;
    Scripter.Execute;
    ShowMessage('Value of MyVar variable in Delphi is '+VarToStr(MyVar));
    ShowMessage('Value of ZipCode variable in Delphi is '+VarToStr(ZipCode));
    end;

    脚本:
    ShowMessage('Today is '+DateToStr(Date)+' in old short date format');
    ShortDateFormat:='dd-mmmm-yyyy';
    ShowMessage('Now today is '+DateToStr(Date)+' in new short date format');
    ShowMessage('My var value was "'+MyVar+'"');
    MyVar:='My new var value';
    ShowMessage('Old Zip code is '+ZipCode);
    ZipCode:='109020';
    ShowMessage('Application tag is '+IntToStr(Application.Tag));

    调用函数和过程
    在脚本中,函数和过程是增加如同方法,差别是你不能增加过程在任何一个类,但是在脚本自己,使用DefineMethod方法,下面的例子说明如

    何增加QuotedStr和StringOfChar方法:
    脚本:
    ShowMessage(QuotedStr(StringOfChar('+',3)));

    代码:
    { TSomeLibrary }
    procedure TSomeLibrary.Init;
    begin
    Scripter.DefineMethod('QuotedStr',1,tkString,nil,QuotedStrProc);
    Scripter.DefineMethod('StringOfChar',2,tkString,nil,StringOfCharProc);
    end;

    procedure TSomeLibrary.QuotedStrProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(QuotedStr(GetInputArgAsString(0)));
    End;

    procedure TSomeLibrary.StringOfCharProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(StringOfChar(GetInputArgAsString(0)[1],GetInputArgAsInteger(1)));
    end;

    procedure TForm1.Run1Click(Sender: TObject);
    begin
    Scripter.AddLibrary(TSomeLibrary);
    Scripter.SourceCode:=Memo1.Lines;
    Scripter.Execute;
    end;

    使用Libraries
    在脚本中,你可以使用Libraries中已注册的函数和方法,看下面的2段代码,第一段使用库和第二段使用一般的文档机制:
    代码1:
    type
    TExampleLibrary = class(TatScripterLibrary)
    protected
    procedure CurrToStrProc(AMachine: TatVirtualMachine);
    procedure Init; override;
    end;

    procedure TExampleLibrary.Init;
    begin
    Scripter.DefineMethod('CurrToStr',1,tkInteger,nil,CurrToStrProc);
    end;

    procedure TExampleLibrary.CurrToStrProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(CurrToStr(GetInputArgAsFloat(0)));
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    Scripter.AddLibrary(TExampleLibrary);
    Scripter.SourceCode:=Memo1.Lines;
    Scripter.Execute;
    end;

    代码2:
    procedure TForm1.PrepareScript;
    begin
    Scripter.DefineMethod('CurrToStr',1,tkInteger,nil,CurrToStrProc);
    end;

    procedure TForm1.CurrToStrProc(AMachine: TatVirtualMachine);
    begin
    With AMachine do
    ReturnOutputArg(CurrToStr(GetInputArgAsFloat(0)));
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    PrepareScript;
    Scripter.SourceCode:=Memo1.Lines;
    Scripter.Execute;
    end;

    两段代码都做同样的事情:增加CurrToStr过程到脚本,注意脚本的初始化方法(代码1的初始化和代码2的PrepareScript)是一样的,和CurrT

    oStrProc方法-没有差别。这两段代码间的差别是:
    - 类和方法的属于,在代码1,方法属于一个专门的类TExampleLibrary,它是从TatScripterLibrary继承下来的,在代码2,它属于当前窗口

    (TForm1)。
    - 在代码1,脚本是增加一个类TExampleLibrary到它自己,使用AddLibrary方法,在代码2,PrepareScript方法是直接调用。

    除了使用AddLibrary方法,你可以使用RegisterScripterLibrary过程,见例子:
    RegisterScripterLibrary(TExampleLibrary);
    RegisterScripterLibrary是注册Library到一个全局列表到一个全局过程,所有脚本都会自动应用到Library,如果你想所有脚本组件都能使用

    Library,就使用RegisterScripterLibrary。使用AddLibrary只能增加一个Library到指定的组件。

    TatPascalFormScripter组件和TatBasicFormScripter组件
    TatPascalFormScripter组件和TatBasicFormScripter组件是从TatPascalScripter组件和TatBasicScripter组件继承下来的。它们都拥有祖先

    的所有功能,同时又注册了自己所特有的功能。
    因此,如果你想要在窗口中使用脚本访问组件,类似于按钮、编辑框等等,你可以在脚本中注册窗口组件。

  • 相关阅读:
    一行代码解析复杂JSON文件:利用Android自带的包解析JSON
    人生的真相
    为我的外婆写上我的挽歌
    总结2016 展望2017
    [转贴]使用CryptoAPI解析X509证书和P12证书
    2015这一年的进步
    怎样在WINDOWS下面编译LIBCURL
    LINQ TO SQL 怎样 执行存储过程并返回存储过程的临时表
    C调用OPENSSL做REST服务客户端的例子
    一个CLI的 的例子
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/2940833.html
Copyright © 2020-2023  润新知