Qt 5.5 中Qt Script翻譯 (一)
找了半天關於QtScript的中文文件很少,只能檢視英文文件,順便翻譯一下。
Qt對基於ECMAScript的指令碼提供了支援,下面的指導和參考涵蓋了ECMAScript和Qt的各個方面。
指令碼類
下面的類將指令碼的功能新增到Qt應用程式當中。
QScriptClass 用於定義自定義的Qt指令碼物件的介面
QScriptClassPropertyIterator 用於遍歷自定義指令碼物件的介面
QScriptContext 一個Qt指令碼函式的呼叫上下文
QScriptContextInfo 關於QScriptContext的額外資訊
QScriptEngine 執行Qt指令碼程式碼的環境
QScriptEngineAgent QScriptEngine執行相關事件的介面
QScriptEngineDebugger QScriptEngine除錯環境
QScriptProgram 封裝了Qt指令碼程式
QScriptString 表示QScriptEngine中字串的控制代碼??
QScriptSyntaxCheckResult 儲存指令碼語法檢查的結果
QScriptValue 表示Qt指令碼資料型別的容器
QScriptValueIterator QScriptValue遍歷器
QScriptable QtC++程式訪問Qt指令碼環境
語言概述
Qt指令碼基於ECMAScript指令碼語言,使用ECMA-262標準。微軟的JScript和網景的javascript也是基於ECMAScript標準,有關 ECMAScript的概述,可以檢視ECMAScript標準。如果你不熟悉ECMAScript語言,有一些指導和書籍,例如JavaScript: The Definitive Guide.
基本用法
為執行指令碼程式碼,你可以建立一個QScriptEngine,然後呼叫它的evaluate()方法,傳入指令碼程式碼作為evaluate()的引數。
QScriptEngine engine;
qDebug() << "the magic number is:" << engine.evaluate("1 + 2").toNumber();
返回值是evaluate()執行的結果,這個結果可以轉換為標準C++和Qt型別。
通過設定指令碼引擎的全域性物件,將自定義屬性註冊到指令碼引擎當中變的很容易。
engine.globalObject().setProperty("foo", 123); qDebug() << "foo times two is:" << engine.evaluate("foo * 2").toNumber();
以上程式碼是將屬性放到指令碼引擎當中,這樣的指令碼程式碼是有效的。
使QObject物件在QScript Engine中有效
在腳本當中任何基於QObject例項是有效的。
將QObject物件傳入QScriptEngine::newQObject()函式當中,這樣Qt指令碼的封裝基於QObject的物件將會被建立,被建立的腳 本物件可以使用QObject的訊號、槽、屬性、和子物件列表。
下面是一個Qobject子類化的例子,該物件在指令碼程式碼中的名字是"myObject"。
QScriptEngine engine;
QObject *someObject = new MyObject;
QScriptValue objectValue = engine.newQObject(someObject);
engine.globalObject().setProperty("myObject", objectValue);
上面的例子,在指令碼環境中建立一個全域性的"myObject"變數,這個變數是一個c++物件的代理。C++物件在指令碼中可以用任何的名稱代指,不依賴上面的QObject::objectName().
newQObject()函式接收兩個額外的可選引數:一個是所有權模式,另一個是可選的允許你控制QScriptValue封裝QObject的行為的容器,我們以後再回顧這些引數。
使用訊號和槽
Qt指令碼適用Qt核心的訊號和槽特性,在Qt腳本當中有三種主要方式使用訊號和槽。
- 混合C++/Script:C++應用程式程式碼連線訊號到一個指令碼函式,例如,指令碼函式可以使使用者打字輸入或者從檔案讀入的。如果你有一個QObject但是不想匯出這個物件到指令碼環境當中,只是想指令碼中定義怎樣響應
一個訊號,並且把在c++中建立連線。 - 混合Script/C++: 對於應用程式匯出到指令碼環境中的物件,指令碼能在該物件上建立訊號和槽的連線,在這種情況下,槽仍然寫在C++端,但是連線完全是指令碼動態定義的。
- 完全指令碼定義:指令碼即能定義訊號處理函式(相當於在Qt指令碼中定義槽),也能設定這些處理程式的連線,例如,指令碼能定義處理QLineEdit::returnPressed()訊號的函式, 然後連線訊號與這個指令碼處理函式。
用qScriptConnect()函式連線c++訊號與指令碼函式,下面的例子是定義了一個連線到QLineEdit::textChanged()訊號的指令碼處理函式:
QLineEdit *edit1 = new QLineEdit(...);
QLineEdit *edit2 = new QLineEdit(...);
QScriptValue handler = eng.evaluate("(function() { print('I am', this.name); })");
QScriptValue obj1 = eng.newObject();
obj1.setProperty("name", "the walrus");
QScriptValue obj2 = eng.newObject();
obj2.setProperty("name", "Sam");
qScriptConnect(edit1, SIGNAL(returnPressed()), obj1, handler);
qScriptConnect(edit2, SIGNAL(returnPressed()), obj2, handler);
我們建立兩個QLineEdit物件並且定義一個簡單的訊號處理函式,連線用同一個處理函式,處理函式根據不同的物件觸發
而使用不同的this物件呼叫,print()程式碼段的輸出將是不同的。
在指令碼程式碼當中,Qt指令碼用不同的句法建立和取消訊號之間的連線,而不是像C++句法那樣只是用QObject::connnect()。您將相關訊號引用為傳送器物件的屬性,並呼叫其connect()。有三個connect()的過載,每個都有一個相應的disconnect()過載。下面的小節描述了這三種形式。
- 函式連線的是訊號(訊號連線訊號)
connect(function)
這種連線情況下,connect()的引數是連線到訊號的處理函式
function myInterestingScriptFunction() {
// ...
}
// ...
myQObject.somethingChanged.connect(myInterestingScriptFunction);
引數可以是指令碼函式,例如上面的例子。也可以是一個QObject物件的slot函式,像下面的例子:
myQObject.somethingChanged.connect(myOtherQObject.doSomething);
當引數是一個QObject物件的slot函式時,訊號和槽的引數型別可以不相容。如果必要,Qt Script將執行訊號引數的轉換,以匹配時隙的引數型別。
取消訊號的連線,你可以呼叫這個訊號的disconnect()函式,傳遞取消連線的引數:
myQObject.somethingChanged.disconnect(myInterestingFunction);
myQObject.somethingChanged.disconnect(myOtherQObject.doSomething)
當connect()只有一個引數時,this物件將是 Global Object。
- 訊號連線到成員函式
connect(thisObject, function)
在這種連線方式下,第一個引數是繫結到this變數,第二個引數是被呼叫的函式。
在這種方式下,如果你有一個push button,你通常想在button的點選訊號觸發是做一些事情,在這種情況下,作為該物件傳遞窗體是有意義的。
var obj = { x: 123 };
var fun = function() { print(this.x); };
myQObject.somethingChanged.connect(obj, fun);
取消訊號的連線,將同樣的引數傳遞到disconnect()中:
myQObject.somethingChanged.disconnect(obj, fun);
- 命名成員函式連線的訊號
connect(thisObject, functionName)
在這種連線方式下,第一個引數是繫結到this的變數,當訊號的響應函式是被呼叫的,第二個引數指定訊號的處理函式,這種情況下涉及到處理函式是第一個引數的成員函式。
注意這種情況下處理函式在連線時已經被確定了,而不是在訊號觸發是動態決定的。
var obj = { x: 123, fun: function() { print(this.x); } };
myQObject.somethingChanged.connect(obj, "fun");
取消訊號連線用同樣的引數 傳遞到disconnect() 中:
myQObject.somethingChanged.disconnect(obj, "fun");