QJSEngine实现QtC++与Javascript混合编程

8 篇文章 0 订阅

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值