In contrast to QScriptEngine
, where you can add custom classes if they inherit from QObject
by using the Q_SCRIPT_DECLARE_QMETAOBJECT
macro, the QJSEngine
does not directly provide this functionality.
You can still use the Qt Meta-object system to provide interfaces for Javascript, but you have to instantiate the object in C++ and add it to the Javascript context.
Then its slots, methods defined with Q_INVOKABLE
, and properties defined with Q_PROPERTY
are all accessible from within the Javascript runtime.
Now you can create a factory which creates instances of your custom class CustomClass
for a given QJSEngine
wrapped as Javascript objects:
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;
}
A factory instance needs to be constructed and added to the global object of the Javascript runtime:
QJSEngine engine;
QJSValue factoryObj = engine.newQObject(new CustomClassFactory());
engine.globalObject().setProperty("_customClassFactory", factoryObj);
Now we can construct objects in Javascript with:
var obj = _customClassFactory.createInstance()
As we've come this far, lets additionally inject a constructor for the custom class into the Javascript runtime:
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()"
"}");
Et voilà, now you can construct C++ object in Javascript, like you would custom Javascript classes:
var obj = new CustomClass()
For the mentioned WebSocket
API you could wrap QtWebSocket
for that purpose – that was exactly what I required when I came up with the proposed approach.
Note that for the sake of simplicity I omitted parameters for the constructor, but they can simply be added as well.
PS: I would have added more links to the official documentation, but due to the lack of reputation I'm not allowed to.