我从Qt开始,我的一个项目是使用QJSEngine来评估javascript,我想为脚本提供一个完整的API,包括类和全局函数。
现在我的程序只提供ECMAScript默认的东西(eval,encodeURI,parseInt等等),但是我需要向代码公开一些自定义类,比如浏览器API(WebSocket类,Image类,文档)宾语)。例如:
var obj = new CustomClass("", 0);
var ret = obj.customClassMethod("[...]!");
customFunction(ret);
我需要在C ++中定义类的行为,它无助于评估类定义并让用户代码运行。
答案 0 :(得分:3)
与QScriptEngine
相比,如果您使用Q_SCRIPT_DECLARE_QMETAOBJECT
宏从QObject
继承自定义类,则可以添加自定义类,QJSEngine
不会直接提供此功能。
您仍然可以使用Qt元对象系统为Javascript提供接口,但您必须在C ++中实例化该对象并将其添加到Javascript上下文中。
然后它的插槽,用Q_INVOKABLE
定义的方法和用Q_PROPERTY
定义的属性都可以在Javascript运行时内访问。
现在,您可以创建一个工厂,为包含为Javascript对象的给定CustomClass
创建自定义类QJSEngine
的实例:
class CustomClassFactory : public QObject
{
Q_OBJECT
public:
CustomClassFactory(QJSEngine* engine) : m_engine(engine) {}
Q_INVOKABLE QJSValue createInstance() {
// The engine takes ownership and destroys the object if no longer required.
return m_engine->newQObject(new CustomClass());
}
private:
QJSEngine* m_engine;
}
需要构建工厂实例并将其添加到Javascript运行时的全局对象中:
QJSEngine engine;
QJSValue factoryObj = engine.newQObject(new CustomClassFactory());
engine.globalObject().setProperty("_customClassFactory", factoryObj);
现在我们可以用Javascript构建对象:
var obj = _customClassFactory.createInstance()
正如我们到目前为止,让我们另外将自定义类的构造函数注入Javascript运行时:
QJSEngine engine;
// Again, the QJSEngine will take ownership of the created object.
QJSValue factoryObj = engine.newQObject(new CustomClassFactory());
engine.globalObject().setProperty("_customClassFactory", factoryObj);
engine.evaluate(
"function CustomClass() {"
" return _customClassFactory.createInstance()"
"}");
Etvoilà,现在您可以在Javascript中构建C ++对象,就像您将自定义Javascript类一样:
var obj = new CustomClass()
对于上面提到的WebSocket
API,您可以为此目的包装QtWebSocket
- 这正是我提出建议方法时所需要的。
请注意,为了简单起见,我省略了构造函数的参数,但也可以简单地添加它们。
PS:我会在官方文档中添加更多链接,但由于缺乏声誉,我不允许这样做。答案 1 :(得分:3)
在Qt 5.8中,新功能添加到QJSEngine:newQMetaObject
您只需添加静态元对象,例如使用上述功能&MyQObjectDerivedClass::staticMetaObject
到JSEngine。
随后,您将能够从QML中new
用Javascript来访问那些对象。我发现这是一个非常简洁的解决方案。
正如文档所述,您必须将您标记为构造函数Q_INVOKABLE
,否则您将无法实例化类的对象。
属性系统(设置程序/获取程序)和插槽一样工作正常。
https://doc.qt.io/qt-5/qjsengine.html#newQMetaObject
这是我的测试代码-首先是添加元对象的C ++部分
QQmlApplicationEngine engine;
QJSValue jsMetaObject = engine.newQMetaObject(&MyClassOfObject::staticMetaObject);
engine.globalObject().setProperty("MyClassOfObject", jsMetaObject);
我现在可以编写news
这种类型的对象并使用setter / getters等的JS。此代码实际上存在于MouseArea onClicked处理程序中,用于手动测试。
var bob = new MyClassOfObject();
print(bob.x);
bob.x = 918264;
print(bob.x);
print(bob.words);
这是类定义...
class MyClassOfObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int x READ getX WRITE setX)
Q_PROPERTY(int y READ getY WRITE setX)
Q_PROPERTY(QStringList words READ getWords)
public:
Q_INVOKABLE explicit MyClassOfObject(QObject *parent = nullptr);
public slots:
int getX() const { return x; }
int getY() const { return y; }
void setX(int x) { this->x = x; }
void setY(int y) { this->y = y; }
QStringList getWords() const;
private:
int x = -113;
int y = 616;
QStringList stringList;
};
答案 2 :(得分:0)
如果您查看QScriptEngine的文档,或者通过搜索“QScriptEngine示例”,您可以找到有关为QScriptEngine提供自定义C ++类的一些内容。
这是一个很好的起点: link to example
QScriptEngine与QJsEngine非常相似,所以对你来说不应该是一个大问题。
希望这会有所帮助:)
答案 3 :(得分:0)
从Qt5.5开始,QScriptEngine
已过时,因此以后仅应使用QJsEngine
。
https://wiki.qt.io/New_Features_in_Qt_5.5#Deprecated_Functionality