2019/09/03

Script Engine in Delphi


圖片來源:網路

系統維護一段時間之後,總會遇到各式各樣的需求,哪怕是改字改公式這樣的小需要,都必須把專案修改後重新編譯以及發佈這樣的改版模式,才能讓使用者順利使用。

『如果有一套語言引擎嵌入到系統中,我只需要改腳本就能夠無痛更新。』

這樣的念頭在我腦海中出現,有想法就來試試看。

在開始之前,自造輪子不如使用輪子,來看看 3rd party 有沒有好用的函式庫可以使用,如果有就不需要再重新寫起。


Devart 的  VirtualDAC (建議售價:79.95 鎂起)

VirtualDAC 的 VirtualQuery 概念圖 (圖片來源:Devart)
資料庫應用裡最常使用到的就是 TDataSet,VirtualQuery 特色就是【利用 SQL 語言把多個 TDataSet 串起來,成為新的資料集】,支援 SQL92,經常需要做各種資料集統計時,這組元件可以省下很多寫 SQL 的時間。

JSEngine (建議售價:80 鎂起)

JSEngine 展示畫面 (圖片來源:WinSoft)
使用 JavaScript Engine 作為基底,可以在應用程式中寫簡單的 JavaScript 語言並且能和 Delphi 程式交互使用,使用 JavaScript 能寫出更為複雜的商業程式內容,而且還不用重新編譯就能執行,使用價值相當高的工具。

ScriptGate (Open source for FireMonkey)

ScriptGate 官網

包裝 TWebBrowser,讓 Delphi 利用它和 JavaScript 進行交互作業,從 Delphi 10.2 開始支援,使用 FireMonkey 框架,也能夠順利跨平台,有多平台開發的需求者一定要來試用看看。


其它對我而言學習曲線蠻高的,以上就我可以理解使用的項目分享給大家參考。


因為現有的專案仍舊是 VCL,所以 ScriptGate就無法應用在專案裡面,不過,既然可以透過 TWebBrowser 來和 JavaScript 互動,想必 VCL 應該也能如法泡製才是。

ScriptGate for VCL DIY

本著踩在巨人的肩膀上看世界為原則,谷哥哥給了一個令人驚奇的答案:


果然已經有人做好了!


在 http://delphidabbler.com 裡的 Article 14 和 21 兩篇文章,就已經有 ScriptGate 的內容了。
感謝 Mauricio Julio 貢獻,讓我們可以用到這麼好的作品
有了工具,再來就是實作,最重要的就是腳本了:

HTML & JavaScript

在這邊重點有兩個:
  • JavaScript DoEval function
輸入運算式並將運算結果傳到【result】Input 標籤裡。
  • Input tag
不顯示,只用來記錄 DoEval 運算結果。

Delphi

在Delphi中主要還是對TWebBrowser進行存取,文章的範例不難,在這邊複製貼上:


function ExecuteJavaScript(WebBrowser:TWebBrowser; Code: string):Variant;
var
  Document:IHTMLDocument2;
  Window:IHTMLWindow2;
begin
  // execute javascript in webbrowser
  Document:=WebBrowser.Document as IHTMLDocument2;
  if not Assigned(Document) then Exit;
  Window:=Document.parentWindow;
  if not Assigned(Window) then Exit;
  try
    Result:=Window.execScript(Code,'JavaScript');
  except
    on E:Exception do raise Exception.Create('Javascript error '+E.Message+' in: '#13#10+Code);
  end;
end;
 
function GetElementIdValue(WebBrowser:TWebBrowser; TagName,TagId,TagAttrib:String):String;
var
  Document: IHTMLDocument2;
  Body: IHTMLElement2;
  Tags: IHTMLElementCollection;
  Tag: IHTMLElement;
  I: Integer;
begin
  Result:='';
  if not Supports(WebBrowser.Document, IHTMLDocument2, Document) then
    raise Exception.Create('Invalid HTML document');
  if not Supports(Document.body, IHTMLElement2, Body) then
    raise Exception.Create('Can''t find  element');
  Tags := Body.getElementsByTagName(UpperCase(TagName));
  for I := 0 to Pred(Tags.length) do begin
    Tag:=Tags.item(I,EmptyParam) as IHTMLElement;
    if Tag.id=TagId then Result:=Tag.getAttribute(TagAttrib,0);
  end;
end;



TWebBrowser 在存取上其實還有些細節,不一定要用 UWebBrowserWrapper 單元,但用它不吃虧,於是最終測試碼如下:

procedure TForm2.Button2Click(Sender: TObject);
var
  LWbWra: TWebBrowserWrapper;
begin
  LWbWra := TWebBrowserWrapper.Create(WebBrowser1);
  try
    LWbWra.NavigateToLocalFile(ExtractFilePath(Application.ExeName)+'test1.htm');
    ExecuteJavaScript(LWbWra.WebBrowser,'DoEval("'+Edit1.Text+'");');
    Caption := GetElementIdValue(LWbWra.WebBrowser,'input','result','value');
  except
    on E:Exception do
      raise E
  end;
  LWbWra.Free;
end;


每一次的呼叫都會重新載入 HTML 檔案,所以修改完就可即時測試程式內容。


由於 Delphi 所附的 TWebBrowser 的核心是系統內的 Internet Explorer (IE),因此在 JavaScript 的支援上要留意 OS 各版的相容性,這點請開發者務必要留意。


以上各家的 Script Engine 提供給大家參考。 下次見 ^_^


See also :

沒有留言:

張貼留言

ebook【Delphi跨平台資料庫程式設計火速上手】電子書出版 (CHT)

Delphi 跨平台資料庫程式設計火速上手,是本關於整合 Delphi 的跨平台技術打造 2-Tier 架構的跨平台 APP 的入門技術書。 全書沒有需要理解的技術知識,只講套路。 力求短時間把製作 APP 的工法熟悉,未來要開發其它的應用程式也能舉一反三。 底下...