Qt提供了對Javascript的良好支持, 若是查閱過文檔你就知道Qt有兩個不一樣的Js封裝引擎:html
QScriptEngine出現的比較早(自Qt4.3始),基於WebKit的JavaScriptCore引擎,提供的api相對來講比較豐富,可是已經被官方標註爲deprecated;QJSEngine則是從Qt5.0開始提供,基於谷歌的V8引擎,是官方建議使用的版本。至於爲何QScriptEngine會被Qt廢棄,各類緣由就比較複雜了,有興趣的朋友能夠看這個連接,我這裏簡要歸納講一下Qt js模塊的實現歷史及緣由:java
功能落後、運行很是慢
。暴露了實現細節
。一些原有函數沒法實現(例如QScriptContext)
。沒有一個穩定的API
來供QtScript實現想要的功能,每一次引擎的變化都須要QtScript模塊內部進行大的調整。V8對外提供的API穩定
,可嵌入
到程序中;可是V8與JavaScriptCore內部細節不一樣,QtScript API的某些概念沒法天然映射到V8上,用V8實現相同性能的舊接口須要至關大的投入,然而QML團隊沒法接受這樣的投入花費。從兩個主要的引擎類上來講,相比QScriptEngine,雖然QJSEngine出來的遲,可是核心的功能(加粗)也是支持的,僅在其餘一些小功能上有所欠缺(未加粗):git
可是畢竟對JavaScriptCore引擎的封裝比較成熟,從QScriptEngine衍生出的技術支持確定是比較豐富,使用也較爲方便。例如QtScript模塊同時包含QScriptClassPropertyIterator
類來提供java風格的屬性遍歷功能、QScriptContext
類來提供上下文信息,等等。可是隨着Qt新版本的發佈,QJsEngine確定是愈來愈成熟的。須要注意的是,這兩個應該都不能與Qt的Web模塊交互使用(親測QJSEngine與QWebEngineView交互無效),畢竟都分紅了兩個不一樣的模塊。github
這裏咱們簡單學習QJSEngine,一如既往,咱們經過一個小例子來學習當前js引擎提供的主要功能, 實際上使用很是簡單。api
QJSValue QJSEngine::evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1)函數
咱們只須要把包含js代碼的字符串傳給QJSEngine::evaluate()
這個函數,就能夠直接執行該js代碼。該函數的後兩個參數是可選的文件名和行號,會在js出錯的時候包含在出錯信息裏。示例程序中當用戶點擊執行按鈕,咱們直接就執行用戶輸入的js代碼:性能
void MainWindow::on_buttonEvaluateJs_clicked(bool) { ui->lineEditJsResult->setText( m_jsEngine.evaluate(ui->lineEditEvaluateJs->text()).toString()); ui->lineEditJsResult->setEnabled(ui->buttonEvaluateJs->isEnabled()); }
QJSValue QJSEngine::globalObject() const
QJSValue QJSEngine::newObject()
void QJSValue::setProperty(const QString &name, const QJSValue &value)學習
經過globalObject()
函數咱們得到Js引擎的全局變量,這個變量是一個QJSValue,是Qt對Js數據類型的一個封裝,基本上支持全部Js對象的操做。例如,咱們能夠判斷兩個QJSValue是否相等、是否嚴格相等、設置屬性、設置原型等。全局對象就是一個能夠在Js代碼中直接使用的Js變量,一般咱們作的就是在C++代碼裏設置全局變量的屬性,而後在Js中直接使用。優化
newObject()
函數用來新建一個Js對象,示例中咱們在新建的Js對象上分別設置3個屬性(setProperty()
)爲用戶輸入的左操做數、右操做數和運算符,而後把這個對象設置爲全局對象的一個屬性,接着咱們在Js代碼中直接調用這3個屬性來進行計算:ui
void MainWindow::on_buttonEvaluatePropertyCalculateResult_clicked(bool) { auto jsObject = m_jsEngine.newObject(); jsObject.setProperty("leftOperand", ui->lineEditPropertyLeft->text()); jsObject.setProperty("rightOperand", ui->lineEditPropertyRight->text()); m_jsEngine.globalObject().setProperty("cppObject", jsObject); ui->lineEditEvaluatePropertyResult->setText(m_jsEngine.evaluate( "cppObject.leftOperand" + ui->lineEditPropertyOperator->text() + "cppObject.rightOperand").toString()); ui->lineEditEvaluatePropertyResult->setEnabled( ui->buttonEvaluatePropertyCalculateResult->isEnabled()); }
QJSValue newQObject(QObject *object)
Signals and slots, properties and children of object are available as properties of the created QJSValue.
經過newQObject()
這個函數,咱們能夠將Qt類封裝成Js對象,集成到Js引擎中。Qt類的信號槽、屬性和子對象能夠在Js中經過屬性來使用,Qt提供強大的本地功能支持,Js提供靈活的使用方式,想一想就很激動。咱們能夠藉此在Js中操控導出的Qt對象、更改界面外觀、實現程序功能的腳本化。
示例中咱們導出街面上的一個QPushButton,把它設置爲Js引擎全局對象的一個屬性:
m_jsEngine.globalObject().setProperty("cppButton", m_jsEngine.newQObject(ui->buttonChangeInJs));
當用戶點擊這個按鈕的時候,咱們讀取本地的Js文件到QString中並執行這段代碼,該Js代碼會調用setStyleSheet()
函數(注意這是一個slot)來更改這個按鈕的外觀樣式:
void MainWindow::on_buttonChangeInJs_clicked(bool) { QFile jsFile(":/js/demo.js"); if (jsFile.open(QIODevice::ReadOnly | QIODevice::Text)) { auto jsStr = QString::fromStdString(jsFile.readAll().toStdString()); auto jsResult = m_jsEngine.evaluate(jsStr); if (jsResult.isError()) ui->buttonChangeInJs->setText(jsResult.toString()); } } function func() { cppButton.setStyleSheet('QPushButton { background-color: qlineargradient(\ x0:0, y0:0, x1:1, y1:1, \ stop: 0.0 #111111,\ stop: 0.2 #222222,\ stop: 0.4 #444444,\ stop: 0.6 #888888,\ stop: 0.8 #aaaaaa,\ stop: 1.0 #ffffff);\ color:white;}\ QPushButton:hover { border:2px solid blue;\ padding:1ex; }\ QPushButton:pressed { background-color: qlineargradient(\ x0:0, y0:0, x1:1, y1:1, \ stop: 0.0 #ff1111,\ stop: 0.2 #22ff22,\ stop: 0.4 #4444ff,\ stop: 0.6 #88ee88,\ stop: 0.8 #aaeeaa,\ stop: 1.0 #ffffff); }') cppButton.text = 'Changed in JS' } func()
完整代碼見連接。