QJSEngine类提供了一个评估JavaScript代码的环境,基于属性来实现的一套与JavaScript交互的机制
一、脚本的基本用法
先来熟悉一些Javascript脚本范例:
function uniOnMenuClick(int a)
{
}
function uniOnMouseDown()
{
return 1;
}
引擎的配置:globobject()函数返回与脚本引擎关联的全局对象。全局对象的属性可以从任何脚本代码中访问(即它们是全局变量)。通常,在评估“user”脚本之前,你需要通过向全局对象添加一个或多个属性来配置脚本引擎:
myEngine.globalObject().setProperty("myNumber", 123);
...
QJSValue myNumberPlusOne = myEngine.evaluate("myNumber + 1");
QJSEngine 执行脚本内容的函数是QJSValue QJSEngine::evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1) 该函数把脚本代码在全局对象的上下文中计算。换言之,只要我们通过evaluate之后就可以通过QJSEngine引擎的全局对象globalObject()的属性property()和脚本函数名称获得这个脚本函数对象QJSValue。
先来看看 QJSValue对象支持JavaScript哪些数据类型
一般来说 简单类型相对简单 比如 JavaScript脚本字符串类型对应QString,但在实际应用过程中更多的来说 JavaScript脚本编写一些配置信息,而且配置信息相对都多,那么这个时候脚本使用数组就很方便了。那如何实现这部分功能呢?如下示例:
QJSValue object;
...
QJSValueIterator it(object);
while (it.hasNext()) {
it.next();
if(it.name() == "test")
qDebug() << it.name() << ": " << it.value().toString();
}
注意:此时QtC++暴露给脚本的接口参数应当类似void init(const QJSValue info);
那如何从C++向Javascript脚本传递参数?
//使用开头的脚本范例
QJSValue function = engine->globalObject()->property("uniOnMenuClick");
QJSValueList args;
args << 10;
if (function.isCallable())
{
QJSValue err = function.call(args);
if (err.isError())
qDebug()<<"error"<< err.toString();
}
二、脚本化
对于较大的功能块,您可能希望将代码和数据封装到模块中。模块是一个包含脚本代码、变量等的文件,并使用export语句来描述它对应用程序其余部分的接口。在import语句的帮助下,模块可以引用其他模块的功能。这允许以安全的方式从较小的连接构建块构建脚本化应用程序。相比之下,使用evaluate()的方法有这样的风险,即来自一次evaluate()调用的内部变量或函数意外地影响了全局对象
下面的例子提供了一个可以添加数字的模块:
export function sum(left, right)
{
return left + right
}
这个模块可以用QJSEngine::import()加载,如果它被保存在math.mjs的名字下:
QJSvalue module = myEngine.importModule("./math.mjs");
QJSValue sumFunction = module.property("sum");
QJSValue result = sumFunction.call(args);
模块还可以使用import语句从其他模块中使用功能:
import { sum } from "./math.mjs";
export function addTwice(left, right)
{
return sum(left, right) * 2;
}
脚本对象的创建:
使用newObject()创建一个JavaScript对象;这是相当于脚本语句new Object()的c++版本。你可以使用QJSValue中特定于对象的功能来操作脚本对象(例如QJSValue::setProperty())。类似地,使用newArray()创建一个JavaScript数组对象。换句话说,一旦使用了newObject之后就可以在JavaScript中直接使用这个对象属性和函数方法。使用newQObject()包装一个QObject(或子类)指针。newQObject()返回代理脚本对象;QObject的属性、子属性、信号和槽都可以作为代理对象的属性使用。不需要绑定代码,因为它是使用Qt元对象系统动态完成的。
QPushButton *button = new QPushButton;
QJSValue scriptButton = myEngine.newQObject(button);
myEngine.globalObject().setProperty("button", scriptButton);
myEngine.evaluate("button.checkable = true");
qDebug() << scriptButton.property("checkable").toBool();
scriptButton.property("show").call(); // call the show() slot
使用newQMetaObject()包装一个QMetaObject;这为您提供了基于qobject类的“脚本表示”。newQMetaObject()返回代理脚本对象;类的枚举值可作为代理对象的属性使用。可以从脚本中调用暴露给元对象系统的构造函数(使用Q_INVOKABLE),以使用javascriptowership创建一个新的QObject实例。例如,给定下面的类定义:
class MyObject : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE MyObject() {}
};
//该类的staticMetaObject可以像这样暴露给JavaScript:
QJSValue jsMetaObject = engine.newQMetaObject(&MyObject::staticMetaObject);
engine.globalObject().setProperty("MyObject", jsMetaObject);
//类的实例可以在JavaScript中创建:
engine.evaluate("var myObject = new MyObject()");
注意:目前只支持使用Q_OBJECT宏的类;不可能将Q_GADGET类的staticMetaObject公开给JavaScript
JSEngine 不支持动态QObject属性,例如以下代码不会工作:
QJSEngine engine;
QObject *myQObject = new QObject();
myQObject->setProperty("dynamicProperty", 3);
QJSValue myScriptQObject = engine.newQObject(myQObject);
engine.globalObject().setProperty("myObject", myScriptQObject);
qDebug() << engine.evaluate("myObject.dynamicProperty").toInt();