Search code examples
c++qtqmlqqmlcomponentqquickitem

How to get a valid instance of a QQuickItem on C++ side


Alright. I have searched a lot but haven't got a good solution yet. I am new to Qt. I have a class which is a QQuickItem like so,

class MyQuickItemClass : public QQuickItem
{
    Q_OBJECT
    SetInfo(SomeCppClass object)
};

I do a qmlRegisterType in my main.cpp to register it on the qml side like this,

qmlRegisterType< MyQuickItemClass >("MyQuickItemClass", 1, 0, "MyQuickItemClass");

All fine till here. But -> I want to set an object instance & some properties in MyQuickItemClass which some C++ logic in it as well & then pass the MyQuickItemClass object to qml. Or, get a valid instance of MyQuickItemClass from Qml. How can I get a vlid instance MyQuickItemClass object instance from QML on C++ side in main.cpp ?

I tried doing the following learning from the link here. But this technique creates two separate objects of MyQuickItemClass. One from QML, & one from c++ side. Hence does not work for me.

Following is how I am trying to do this after lot of searching.

int main(int argc, char *argv[]) 
{
  qmlRegisterType< MyQuickItemClass >("MyQuickItemClass", 1, 0, "MyQuickItemClass");
  QQmlApplicationEngine engine;
  SomeCppClass someCppClassObject;
  someCppClassObject.updateSomething();

  MyQuickItemClass myquickItemObject;
  myquickItemObject.SetInfo(someCppClassObject);
  engine.rootContext()->setContextProperty("myquickItemObject", &myquickItemObject);

  engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
  return app.exec();
}

But, doing the above gets the constructor of MyQuickItemClass called twice. Once from cpp side when I created an object, and once from qml side. Verified this by placing a breakpoint in the constructor of MyQuickItemClass as well. As a result, someCppClassObject that I had set is null inside MyQuickItemClass when program runs. Because qml has made the final call to MyQuickItemClass to instantiate, thusly ignoring the MyQuickItemClass object that I created in main.cpp.

Here is my qml code for MyQuickItemClass:

import QtQuick 2.5
import MyQuickItemClass 1.0

ParentContainerItem {
  id: parentItem
  color: "black"

  MyQuickItemClass {
      id: myQuickItemID
      visible: true
      objectName: "myQuickItem"

      property bool someProperty1: false
      property bool someProperty2: true

      anchors.top: parent.top
      anchors.horizontalCenter: parent.horizontalCenter
  }

  //Other qml components
}

And this is the C++ class whose object needs to be set into MyQuickItemClass.

SomeCppClass {
  //Pure C++ class. No Qt
}

Please note that I need to keep MyQuickItemClass derived from QQuickItem. Please suggest...


Solution

  • Generally it is a good idea to avoid accessing QML instantiated objects from outside as most of the access methods generated a dependency from C++ toward QML, restricting the way the QML tree is done.

    E.g. requiring certain objects to exist at certain point in times, having specific objectName values, etc.

    It is better to either "register" the object from QML side by calling a method on an exposed C++ object/API or to make the QML instantiate object register itself from within its own C++ code.

    The latter is obviously inherently automatic, i.e. each instance of such a class would do that, while the former puts it at the discretion of the QML code which of the created instances it wants to make known.