Qt提供了对Javascript的良好支持, 如果查阅过文档你就知道Qt有两个不同的Js封装引擎:

  • QScriptEngine
  • QJSEngine

QScriptEngine出现的比较早(自Qt4.3始),基于WebKit的JavaScriptCore引擎,提供的api相对来说比较丰富,但是已经被官方标注为deprecated;QJSEngine则是从Qt5.0开始提供,基于谷歌的V8引擎,是官方建议使用的版本。至于为什么QScriptEngine会被Qt废弃,各种原因就比较复杂了,有兴趣的朋友可以看这个链接,我这里简要概括讲一下Qt js模块的实现历史及原因:

  1. QScriptEngine---使用自建的js引擎:功能落后、运行非常慢
  2. QScriptEngine---使用JavaScriptCore引擎(WebKit的主引擎):
    • 由此封装提供的JS API暴露了实现细节
    • 由于设计使用方式的不同一些原有函数无法实现(例如QScriptContext)
    • JavaScriptCore变化太大,没有一个稳定的API来供QtScript实现想要的功能,每一次引擎的变化都需要QtScript模块内部进行大的调整。
  3. QScriptEngine---使用V8引擎:V8对外提供的API稳定可嵌入到程序中;但是V8与JavaScriptCore内部细节不同,QtScript API的某些概念无法自然映射到V8上,用V8实现相同性能的旧接口需要相当大的投入,然而QML团队无法接受这样的投入花费。
  4. QJSEngine-------使用V8引擎。

1. QScriptEngine VS QJSEngine

从两个主要的引擎类上来说,相比QScriptEngine,虽然QJSEngine出来的迟,但是核心的功能(加粗)也是支持的,仅在其他一些小功能上有所欠缺(未加粗):

  • 执行脚本字符串。
  • 引擎全局变量配置。
  • 异常处理。
  • Js对象创建
  • Qt类与Js的交互集成。
  • Js扩展。
  • 自定义C++类(非Qt内建)。
  • C++函数与Js的交互集成。
  • Long-running脚本优化处理。
  • 调试跟踪。

但是毕竟对JavaScriptCore引擎的封装比较成熟,从QScriptEngine衍生出的技术支持肯定是比较丰富,使用也较为方便。例如QtScript模块同时包含QScriptClassPropertyIterator类来提供java风格的属性遍历功能、QScriptContext类来提供上下文信息,等等。但是随着Qt新版本的发布,QJsEngine肯定是越来越成熟的。需要注意的是,这两个应该都不能与Qt的Web模块交互使用(亲测QJSEngine与QWebEngineView交互无效),毕竟都分成了两个不同的模块。

2. QJSEngine介绍

这里我们简单学习QJSEngine,一如既往,我们通过一个小例子来学习当前js引擎提供的主要功能, 实际上使用非常简单。

2.1 执行脚本

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());
}

2.2 配置引擎的全局变量(C++/Js交互)

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个属性来进行计算:

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());
}

2.3 Qt/Js交互(脚本化)

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()

3. 运行结果

完整代码见链接

最新文章

  1. cookie的session_id解释
  2. [转]在WPF中区别TextBlock和Label
  3. C#复习⑦
  4. umeng社交分享最新版5.0的跨进程使用崩溃的问题及解法-Android
  5. KMS10流氓软件
  6. flexigrid扩展(添加全选,格式化表单)
  7. Naive Bayes理论与实践
  8. 【分享送书】NGUI全面实践教程V3.8.2 活动开始了!!
  9. 高效通信模型之 - 网络通信I/O模式( Windows)
  10. IOS中的ViewController 的loadView、viewDidLoad、viewDidUnload
  11. 使用传入的总记录数实现一条sql语句完成分页查询
  12. 学习HTML5的第二周
  13. android自定义view实现公章效果
  14. 使用ranger对kafka进行鉴权
  15. ABP中的依赖注入思想
  16. conda的使用(附带远程文件传输命令)
  17. int与integer的区别
  18. Codeforces300 F. A Heap of Heaps
  19. NOIP2017题解
  20. .NET Entity Framework基本使用方法

热门文章

  1. asp.net web api 构建api帮助文档
  2. 谷歌浏览器 插件安装配置Momentum chrome
  3. Less命名空间
  4. 爱立信开始大规模mesh网络测试
  5. mysql中 union是什么鬼
  6. Linux中nginx手动安装
  7. CentOS7操作系统参数优化
  8. flask_login 整合 pyjwt + json 简易flask框架
  9. axure扫盲
  10. Android研究之监听自身应用被卸载代码实现