Newable script objects: QScriptEngine vs. QQMLEngine/QJSEngine
-
Good morning,
I'm interested in adding C++ objects that can be instantiated from a script but I'm not sure how it works when combined with QtQuick.I'm trying to use the Q_SCRIPT_DECLARE_QMETAOBJECT macro and scriptValueFromQMetaObject<>() method to create newable script objects.
My main creates a QQuickView() object.
That object contains an engine() method that returns a QQmlEngine which inherits from QJSEngine.
The scriptValueFromQMetaObject method is derived from QScriptEngine() not QJSEngine.
I don't see an equivalent of scriptValueFromQMetaObject in QJSEngine.Is there a way to 'register' my C++ class with QJSEngine? I assume I have to use the javascript engine associated with the QML view. That way the class will be available in the script context associated with the QML code.
Thanks!
-
Hi,
I think it is not possible by now to create custom classes that are newable in script code, at least I couldn't figure out how to do it.
As a workaround you can create some sort of QObject derived "master object" that is set as a global property in your script context and give it a Q_INVOKABLE method that acts as factory for the objects, that you want to instantiate dynamically in your script, like:
@
Q_INVOKABLE QObject* myFactoryForObjectsOfTypeA() const {
QObject* obj = new ObjectOfTypeA;
QQmlEngine::setObjectOwnership(obj, QQmlEngine::JavaScriptOwnership);
return obj;
}
@I have working code for this on my harddrive. If you like the idea then I can post a more complete example.
Cheers!
-
I was able to figure out something that might work.
As a work around I declared a function as Q_INVOKABLE in the object that the script context inherits from. In that object I create a javascript compatible object and return it. A simple new myobject() also works but I don't think it confers ownership to the script and it will never be deleted.
@QJSValue contextclass::myobject( int Row, int Column )
{
Application* app = dynamic_cast< Application* >( QCoreApplication::instance() );
if ( !app )
throw ::std::runtime_error( "Could not obtain application object" );
// this confers ownership to javascript but not sure when garbage collection will happen
return app->view->engine()->newQObject( new myobject() );
}
@I also tried the following. It compiled but I never could get the script to invoke it:
@ // create a script wrapped proxy object as a QScriptValue
cellReferenceFactory = view->engine()->newQObject( &_myobject );
// Create a script wrapped QJSValue that will instantiate a new object
cellReferenceInstance = cellReferenceFactory.callAsConstructor();
// tell the engine to create a property that will instantiate a myobject object
view->engine()->globalObject().setProperty( "myobject", cellReferenceInstance );
@I tried to create it using "Qt.myobject" and "Qt.myobject()" ( view is the QQuickView for the application)
-
You could also try to use your C++ object as a prototype:
QJSValue myType = engine->evaluate("function MyType() {}"); myType.setPrototype( engine->newQObject(new MyTypeCpp));
I've not tried this, but this could work. Probably you would to have to set myType as property in the
JSEngine::globalObject()
.