问题
I am starting with Qt and one of my projects is using QJSEngine to evaluate javascript and I want to provide an entire API to the script, with classes and global functions.
Right now my program provides only the ECMAScript default stuff (eval, encodeURI, parseInt, etc...), but I need to expose some custom classes to the code, like the browsers API (WebSocket class, Image class, document object). For example:
var obj = new CustomClass("", 0);
var ret = obj.customClassMethod("[...]!");
customFunction(ret);
I need to define the behavior of the classes in C++, it wouldn't help evaluate the classes definition and let the user code run.
回答1:
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.
回答2:
If you look up Documentation of QScriptEngine, or by searching "QScriptEngine examples" you can find some stuff about making Custom C++ Classes available to QScriptEngine.
Here is a good place to start: link to example
QScriptEngine is very similiar to QJsEngine, so it shouldn't be a big problem for you.
Hope this helps :)
回答3:
As of Qt5.5 QScriptEngine
has been deprecated, so only QJsEngine
should be used in the future.
https://wiki.qt.io/New_Features_in_Qt_5.5#Deprecated_Functionality
来源:https://stackoverflow.com/questions/19171139/how-to-build-an-api-with-qjsengine