QScriptEngine类的使用

https://doc.qt.io/qt-5/qscriptengine.html

https://blog.csdn.net/shuangguo121/article/details/37958997?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=2

在这里插入图片描述

globalobject()
这也是一个 QScriptValue,通过设置它的属性,可以在脚本中访问C++中的数据和对象

接前面的例子,在执行脚本前,添加一句:

engine.globalObject().setProperty("a", 123);

使得整数123在脚本中作为a被访问。

其实就是几步

头文件包含

#include
#include

//构造 Script 的 engine 这个可以一直使用,但值得注意的是,这个构造必须要在Q(Core)Application 构造后才能开始构造
QScriptEngine engine;

//设置对象,这一步是对Script声明变量的方式,被用于声明的类地址,必须是由QObject继承下来的完整的类

CMyObj obj;
QScriptValue o = engine.newQObject(&obj);
engine.globalObject().setProperty("abc", o);

//执行这个script,因为之前把obj定义成了abc这个名字,所以这里是abc.test(), 这里值得注意的是,CMyObj 这个类的 test() 必须有 Q_INVOKABLE 修饰,否则找不到这个函数
engine.evaluate(“abc.test()”);

原文链接:https://blog.csdn.net/dronly/article/details/17247531

QScriptEngine类

QScriptEngine类提供用于解释的Qt Script代码的环境。

包含:QScriptEngine
继承关系:QObject的子类

例一:

QScriptEngine myEngine;
QScriptValue three = myEngine.evaluate("1 + 2");

evaluate()返回一个QScriptValue保存的解释结果。该QScriptValue类提供函数计算结果并转换为不同的C++类型(例如QScriptValue:: toString()和QScriptValue:: toNumber())。

例二:

下面的代码片段显示了一个脚本函数被定义,然后从C++中调用使用QScriptValue:: ()的调用的例子:

QScriptValue fun = myEngine.evaluate("(function(a, b)  { return a + b; })");
QScriptValueList args;
args << 1 << 2;
QScriptValue threeAgain = fun.call(QScriptValue(), args);

如可以从上面的代码段中可以看出,一个脚本被以字符串的形式提供给解释引擎。加载脚本的一种常见方法是通过读取一个文件的内容,并通过它来evaluate(),如下代码:

QString fileName = "helloworld.qs";
QFile scriptFile(fileName);
if (!scriptFile.open(QIODevice::ReadOnly))
    // handle error
QTextStream stream(&scriptFile);
QString contents = stream.readAll();
scriptFile.close();
myEngine.evaluate(contents, fileName);

上面我们通过文件名作为第二个参数来evaluate()。这并不影响解释的方式,第二个参数是用来识别脚本用于调试目的的general-purpose字符串(例如,我们的文件名现在将要通过uncaughtExceptionBacktrace() involving到脚本)。

引擎配置

globalObject()函数返回与脚本引擎相关联的全局对象。全局对象的属性可从任何脚本代码访问(也就是说,它们是全局变量)。通常情况下,解释脚本之前,你会希望通过添加一个或多个属性的全局对象来配置脚本引擎:

myEngine.globalObject().setProperty("myNumber", 123);
...
QScriptValue myNumberPlusOne = myEngine.evaluate("myNumber + 1");

添加自定义属性的脚本环境或提供脚本API是脚本相对于应用程序定制的标准方法之一。通常这些自定义属性有由newQObject()或newobject()函数,或者通过newFunction(创建构造函数)创建的对象。

脚本异常

evaluate()可以抛出一个脚本异常(如由于语法错误);在这种情况下,返回值是一个被抛出(通常是一个错误的对象)的值。您可以检查是否解释器通过调用hasUncaughtException()导致了异常。在这种情况下,你可以调用的错误对象的toString()来获取错误消息。对于目前未捕获的异常,也可通过uncaughtException()。调用clearExceptions()将导致任何未捕获的异常被清除。

QScriptValue result = myEngine.evaluate(...);
if (myEngine.hasUncaughtException())  {
    int line = myEngine.uncaughtExceptionLineNumber();
    qDebug() << "uncaught exception at line" << line << ":" << result.toString();
}

checkSyntax()函数可以被用来确定是否代码已经有效地传递到evaluate()。

脚本对象的创建

使用newobject()来创建一个标准的Qt Script对象;这是相当于C++的new Object()。您可以使用该对象的特定功能,在QScriptValue操纵脚本对象(例如QScriptValue::的setProperty())。同样,使用newArray()来创建一个Qt脚本数组对象。使用newDate()来创建一个日期对象,newRegExp()来创建一个RegExp对象等都是被允许的。

QObject的整合

使用newQObject()来包装一个QObject的(或子类)的指针。newQObject()返回一个代理脚本对象、特性、子类、信号或QObject的槽,它可作为代理对象的属性。不需要任何绑定代码,因为它是使用Qt元对象系统动态地进行管理。

QPushButton button;
QScriptValue scriptButton = myEngine.newQObject(&button);
myEngine.globalObject().setProperty("button", scriptButton);
myEngine.evaluate("button.checkable = true");
qDebug() << scriptButton.property("checkable").toBoolean();
scriptButton.property("show").call(); //调用show()槽

使用qScriptConnect()来一个将一个QT的信号连接到一个脚本函数;这是与Qt脚本的QObject::connect()等效的。当一个脚本函数响应一个C++的信号调用,它可能会导致脚本异常;您可以连接到signalHandlerException()信号捕捉这样的异常。
使用newQMetaObject()来封装一个QMetaObject;这给你一个基于QObject的类的"script representation"。 newQMetaObject()返回一个代理脚本对象;可作为代理对象的属性的类的枚举值。您还可以指定用于构造类的对象(例如,当构造函数是从一个脚本调用)的函数。对于具有“标准”的Qt类的构造函数,Qt的脚本可以为你提供一个默认的构造函数的脚本。详参scriptValueFromQMetaObject()。

请参阅QtScript文档上的QObject集成的详细信息。

导入扩展

使用importExtension()来导入基于插件的扩展到引擎。调用availableExtensions()来获取一个list内含所有可用的扩展。或调用importedExtensions()来获得一个list内含那些已导入扩展。
调用pushContext()打开一个新的变量域,popContext()来关闭当前作用域。如果含临时变量定义(例如var foo = 123;) 要安全的释放时,意味着解释已经完成。 【最后一句拿不准,原文为and popContext() to close the current scope. This is useful if you are implementing an extension that evaluates script code containing temporary variable definitions (e.g. var foo = 123;) that are safe to discard when evaluation has completed.】

原生功能

使用newFunction()来封装原生(C++)函数,包括自己构造自定义类型,然后这些可以从脚本代码被调用。想使用这些功能必须有QScriptEngine:: FunctionSignature()的家长签字。然后你可能会传递函数作为参数传递给newFunction()。这里是一个函数返回它的前两个参数的和的一个例子:

QScriptValue myAdd(QScriptContext *context, QScriptEngine *engine)
 {
   QScriptValue a = context->argument(0);
   QScriptValue b = context->argument(1);
   return a.toNumber() + b.toNumber();
}

若要公开这个功能的脚本代码,可以将其设置为全局对象的一个属性:

QScriptValue fun = myEngine.newFunction(myAdd);
myEngine.globalObject().setProperty("myAdd", fun);

一旦做到这一点,脚本代码可以用完全相同的方式调用你的函数,并作为一个“正常”的脚本函数:

QScriptValue result = myEngine.evaluate("myAdd(myNumber, 1)");

长时间运行脚本

如果您需要解释从主(GUI)线程可能长时间运行的脚本,你应该先调用setProcessEventsInterval(),以确保该图形用户界面保持响应。你可以通过调用abortEvaluation()终止当前正在运行的脚本。你可以通过调用isEvaluating()确定引擎是否正在运行的脚本。

垃圾回收

Qt的脚本对象可以被垃圾回收,若是这样,他们将不再允许被引用。不过没有人知道自动垃圾回收将会何时发生。
CollectGarbage()函数可以被调用来显式地请求垃圾回收。
reportAdditionalMemoryCost()函数可以被调用,以表明一个Qt Script对象占用的并非是由脚本环境管理的内存。报告的额外成本使得垃圾回收器更容易被触发。这可能是有用的,例如在许多Qt规则中,原生的Qt Script对象会被分配。

核心调试/跟踪功能

自Qt的4.4以来,您可以通过QScriptEngineAgent接口获取有关的脚本执行(如脚本函数调用和语句的执行)的事件通知;看到setAgent()函数。这可以被用来实现调试和QScriptEngine的分析。

更多详情,请见QScriptValue,QScriptContext和QScriptEngineAgent等类的说明文档。

Qt 反射,moc,Q_INVOKABLE

使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起

Q_INVOKABLE与QMetaObject::invokeMethod均由元对象系统唤起。这一机制在Qt C++/QML混合编程,跨线程编程,Qt Service Framework 以及 Qt/ HTML5混合编程以及里广泛使用。

一,Qt C++/QML混合编程

二,跨线程编程中的使用
我们如何调用驻足在其他线程里的QObject方法呢?Qt提供了一种非常友好而且干净的解决方案:向事件队列post一个事件,事件的处理将以调用我们所感兴趣的方法为主(当然这需要线程有一个正在运行的事件循环)。而触发机制的实现是由moc提供的内省方法实现的。因此,只有信号、槽以及被标记成Q_INVOKABLE的方法才能够被其它线程所触发调用。如果你不想通过跨线程的信号、槽这一方法来实现调用驻足在其他线程里的QObject方法。另一选择就是将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。

https://www.cnblogs.com/xiangtingshen/p/11387911.html

QTScript绑定C++的几种方法

https://blog.csdn.net/shgaol/article/details/6160331?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6.pc_relevant_default&utm_relevant_index=10

使用newFunction()来封装原生(C++)函数

https://blog.csdn.net/shuangguo121/article/details/37958997?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=2

原生功能
使用newFunction()来封装原生(C++)函数,包括自己构造自定义类型,然后这些可以从脚本代码被调用。想使用这些功能必须有QScriptEngine:: FunctionSignature()的家长签字。然后你可能会传递函数作为参数传递给newFunction()。这里是一个函数返回它的前两个参数的和的一个例子:

QScriptValue myAdd(QScriptContext *context, QScriptEngine *engine)
 {
   QScriptValue a = context->argument(0);
   QScriptValue b = context->argument(1);
   return a.toNumber() + b.toNumber();
}

若要公开这个功能的脚本代码,可以将其设置为全局对象的一个属性:

QScriptValue fun = myEngine.newFunction(myAdd);
myEngine.globalObject().setProperty("myAdd", fun);

一旦做到这一点,脚本代码可以用完全相同的方式调用你的函数,并作为一个“正常”的脚本函数:

QScriptValue result = myEngine.evaluate("myAdd(myNumber, 1)");
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值