使用Qt QJSEngine實現JavaScript與C++混合編程

QJSEngine實現了一個Qt中JavaScript的運行環境,使用的是Chrome的V8引擎。
下面介紹一下QJSEngine的簡單使用。


1. 執行JavaScript的代碼

使用函數 evaluate 實現執行一個JavaScript腳本。

QJSEngine* jsEngine = new QJSEngine(this);
// 執行Js代碼
QJSValue value = jsEngine->evaluate("1+1");
qDebug() << "1 + 1 Result is " << value.toInt();

QJSValue 是一個Qt/JavaScript包裝的一個類型。
也可以使用 QJSValue::call 函數,傳遞參數給一個JavaScript的函數。

QJSValue function = jsEngine->evaluate("(function(a, b){return a + b;})");
QJSValueList args;
args << 10 << 20;
QJSValue funcValue = function.call(args);
qDebug() << "Function Result is " << funcValue.toInt();

2. 腳本異常

在Qt環境中,執行JavaScript函數。如果出現語法錯誤等問題,在Qt環境中是如何獲取的呢?
同樣在腳本執行的 QJSValue 類中,可以獲取是否執行出錯,以及一些錯誤信息。

// Error
QJSValue errorValue = jsEngine->evaluate("...");
if (errorValue.isError())
{
    qDebug() << "Error!";
    qDebug() << errorValue.property("name").toString() << ", " \
             << errorValue.property("message").toString();
    qDebug() << errorValue.property("lineNumber").toInt();
}

輸出結果如下:
Error!
"SyntaxError" , "Expected token `;’"
1

下面是一些可使用的屬性:

  • name : 名字
  • message :錯誤的信息
  • fileName : 文件名,evaluate 函數也可以指定一個文件名,它的作用也僅用於次。如果想加載一個文件運行,則必須加載到內存中,然後將文件的內容傳遞到該函數中。
  • lineNumber :錯誤行號
  • stack :調用堆棧。

3. JavaScript中調用C++

(1)添加全局對象屬性

函數 globalObject() 會返回一個全局對象。

jsEngine->globalObject().setProperty("CustomNumber", 100);
value = jsEngine->evaluate("CustomNumber + 1");
qDebug() << "Result is " << value.toInt();

設置全局屬性 CustomNumber 初始值爲100 。
JavaScript環境中,可以直接使用該屬性。

(2)添加類對象屬性

使用函數 newQObject() 包裹一個 QObject 或者它的子類,返回一個JavaScript的代理類。在這個代理類中,可以使用它的屬性、信號和槽函數。也可以使用函數 newObject() 創建一個普通的JavaScript類對象。

下面是一個簡單的示例:
類聲明:

class JsRunFunc : public QObject
{
    Q_OBJECT

public:
    Q_INVOKABLE JsRunFunc(QObject* parent = nullptr);
    ~JsRunFunc();

    Q_INVOKABLE int callFunc(int number1, int number2);
};

其實現如下:

JsRunFunc::JsRunFunc(QObject* parent)
    :QObject(parent)
{
    qDebug() << __FUNCTION__;
}

JsRunFunc::~JsRunFunc()
{

}

int JsRunFunc::callFunc(int number1, int number2)
{
    qDebug() << __FUNCTION__;
    return number1 + number2;
}

如果想在JavaScript環境中,調用一個 JsRunFunc 的類對象。代碼如下:

JsRunFunc* object = new JsRunFunc(this);
QJSValue jsObject = jsEngine->newQObject(object);
jsEngine->globalObject().setProperty("jsRunFuncObject", jsObject);
  • 使用函數 newQObject 創建一個類對象的代理對象 jsObject
  • 使用函數 globalObject().setProperty 設置全局對象屬性 jsRunFuncObject

這樣就可以在JavaScript環境中,直接使用該對象了

QJSValue value = jsEngine->evaluate("jsRunFuncObject.callFunc(10, 20)");
qDebug() << "CallFunc Result is " << value.toInt();

運行結果爲:
CallFunc Result is 30

這裏需要注意的是,如果JavaScript中想要使用C++類對象的函數,除了信號和槽函數,以及屬性可以直接使用外,可以加宏 Q_INVOKABLE 修飾函數。

(3)添加類屬性

如果想要在JavaScript環境中,添加類屬性使用函數 newQMetaObject() 創建一個類的代理。

示例代碼如下:

QJSValue jsMetaObject = jsEngine->newQMetaObject(&JsRunFunc::staticMetaObject);
jsEngine->globalObject().setProperty("JsRunFunc", jsMetaObject);
jsEngine->evaluate("var obj = new JsRunFunc; var result = obj.callFunc(100, 200); console.log(result)");

這裏需要注意兩點:

  • 類的構造函數中,必須使用宏 Q_INVOKABLE 修飾。
  • 類中必須使用宏 Q_OBJECT

此外,可以使用函數 installExtensions 安裝一些擴展的功能。

jsEngine->installExtensions(QJSEngine::TranslationExtension | QJSEngine::ConsoleExtension);

作者:douzhq
個人博客主頁:不會飛的紙飛機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章