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.


  • 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.


  • 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().

Log in to reply