Qt 提供了对 Javascript 的良好支持, 如果查阅过文档你就知道 Qt 有两个不同的 Js 封装引擎:
QScriptEngine 出现的比较早(自 Qt4.3 始),基于 webKit 的 JavaScriptCore 引擎,提供的 api 相对来说比较丰富,但是已经被官方标注为 deprecated;QJSEngine 则是从 Qt5.0 开始提供,基于谷歌的 V8 引擎,是官方建议使用的版本。至于为什么 QScriptEngine 会被 Qt 废弃,各种原因就比较复杂了,有兴趣的朋友可以看这个 链接 ,我这里简要概括讲一下 Qt js 模块的实现历史及原因:
。
- 功能落后、运行非常慢
。
- 暴露了实现细节
。
- 一些原有函数无法实现(例如QScriptContext)
来供 QtScript 实现想要的功能,每一次引擎的变化都需要 QtScript 模块内部进行大的调整。
- 没有一个稳定的API
,可嵌入到程序中;但是 V8 与 JavaScriptCore 内部细节不同,QtScript API 的某些概念无法自然映射到 V8 上,用 V8 实现相同性能的旧接口需要相当大的投入,然而 QML 团队无法接受这样的投入花费。
- V8对外提供的API稳定
从两个主要的引擎类上来说,相比 QScriptEngine,虽然 QJSEngine 出来的迟,但是核心的功能(加粗)也是支持的,仅在其他一些小功能上有所欠缺(未加粗):
但是毕竟对 JavaScriptCore 引擎的封装比较成熟,从 QScriptEngine 衍生出的技术支持肯定是比较丰富,使用也较为方便。例如 QtScript 模块同时包含
类来提供 java 风格的属性遍历功能、QScriptContext 类来提供上下文信息,等等。但是随着 Qt 新版本的发布,QJsEngine 肯定是越来越成熟的。需要注意的是,这两个应该都不能与 Qt 的 Web 模块交互使用(亲测 QJSEngine 与 QWebEngineView 交互无效),毕竟都分成了两个不同的模块。
- QScriptClassPropertyIterator
这里我们简单学习 QJSEngine,一如既往,我们通过一个小例子来学习当前 js 引擎提供的主要功能, 实际上使用非常简单。
QJSValue QJSEngine::evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1)
我们只需要把包含 js 代码的字符串传给
这个函数,就可以直接执行该 js 代码。该函数的后两个参数是可选的文件名和行号,会在 js 出错的时候包含在出错信息里。示例程序中当用户点击执行按钮,我们直接就执行用户输入的 js 代码:
- QJSEngine::evaluate()
- 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 个属性来进行计算:
- 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()
完整代码见 链接 。
来源: https://www.cnblogs.com/lgxZJ/p/8158132.html