Search code examples
qtqmlqobject

How can a C++ QObject be created inside a QML javascript function block?


Similar to this question, I want to instantiate a sub-class of QObject, but I want to do this in a javascript function block itself.

I have a class:

class CoverageKind : public QObject {
  Q_OBJECT    
public:

  int64_t        id;
  QString        coverage_kind;

  CoverageKind(QObject * parent=nullptr);

  Q_PROPERTY(int64_t id MEMBER id NOTIFY id_changed)
  Q_PROPERTY(QString coverage_kind MEMBER coverage_kind NOTIFY coverage_kind_changed)

signals:
  void id_changed();
  void coverage_kind_changed();
};

This is registered with QML like:

qmlRegisterType<CoverageKind>("com.example.CoverageKind", 0, 1, "CoverageKind");

After importing com.example.CoverageKind, I can instantiate this QObject subclass like:

Item {
  CoverageKind {
    id: ck
    Component.onCompleted: {
      console.log('Created CoverageKind! ', ck);
    }
  }
}

Which prints:

Created CoverageKind!  CoverageKind(0x19b51b0)

However, if I do:

import com.example.CoverageKind 0.1;
Item {
  CoverageKind ck;
  Component.onCompleted: {
    ck = new CoverageKind();
  }
}

I get TypeError: Type error on the ck = new ... line.

I there an idiomatic way that can I instantiate a C++ QObject subclass from a QML javascript block?

I can do

var ck = Qt.createComponent("import com.example.CoverageKind 0.1; CoverageKind{}");

This feels really clunky. I could also create a factory function, but I was hoping to be able to create these objects inside of javascript more ergonomically.


Solution

  • new does not exist in QML, and the closest thing to what you want is to create property of type CoverageKind that is null initially and in Component.onCompleted you will be assigned the value created with Qt.createQmlObject().

    import QtQuick 2.0
    import com.example.CoverageKind 0.1;
    
    Item {
        id: parentItem
        property CoverageKind ck: null
        Component.onCompleted: {
            ck = Qt.createQmlObject('import com.example.CoverageKind 0.1; CoverageKind{}',
                                    parentItem,
                                    "dynamicSnippet1");
        }
    }