2

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

Community
  • 1
  • 1
TheWaterProgrammer
  • 7,055
  • 12
  • 70
  • 159
  • what error do you get? how is the instance "invalid"? – Hayt Oct 21 '16 at 14:14
  • the constructor of `MyQuickItemClass` gets 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` – TheWaterProgrammer Oct 21 '16 at 14:20
  • You should add the error to the question too. So people who find this question don't have to read through the comments for this. – Hayt Oct 21 '16 at 14:21
  • Ok. added the error to the question now – TheWaterProgrammer Oct 21 '16 at 14:26
  • show us the main.qml – GrecKo Oct 21 '16 at 14:56
  • Why do you recreate it in QML? You can just access your c++ object via `myquickItemObject` in your qml file. – GrecKo Oct 21 '16 at 15:17
  • I updated qml part of my code into the question – TheWaterProgrammer Oct 21 '16 at 15:39
  • @GrecKo please note that `SomeCppClass` is a pure C++ class – TheWaterProgrammer Oct 21 '16 at 16:03
  • you can simply instantiate your `myQuickItemObject` from main.qml as GrecKo says and then pass it as a QObject via signal/slots from qml to C++ and vice versa – mike510a Oct 22 '16 at 09:39
  • @MikeNickaloff . Can you pls explain what you mean by `instantiate myQuickItemObject` ? Is it by creating a block like this in in `qml` ? `myQuickItemObject { id: myobject }` Isnt `myQuickItemObject` already instantiated in qml ? – TheWaterProgrammer Oct 22 '16 at 09:43
  • @NelsonP you already created it in c++, doing `SomeCppClass { }` in qml will create another instance of it. Just access it via `myQuickItemObject` as if it were its' `id`. – GrecKo Oct 22 '16 at 20:54
  • Imagine anytime you register a class using `qmlRegisterType<>()` that you are basically adding a new class-type to QML. It does not matter if that class-type is totally written in C++ or not, you access its methods the same way as in C++ from QML. That being said, all QML items have to be QObject derived, so you can pass an instance of a QML-instantiated object as a QObject to a native C++ typed object by adding to the root context of the QML engine and then passing the desired object via a regular slot; `void send_qml_object(QObject* qmlObject)` from qml: `cppObj.send_qml_object(myobject)` – mike510a Oct 22 '16 at 22:46

2 Answers2

1

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.

Kevin Krammer
  • 5,159
  • 2
  • 9
  • 22
  • Isn't there any way to get a valid instance of `MyQuickItemClass` from the qml objects tree & facilitate myself to call the method `SetInfo` ? Strange !! I thought this would be really simple – TheWaterProgrammer Oct 22 '16 at 16:19
  • 1
    There is, simply search for the object given its object name using `QObject::findChild()`, but why do that if there are much cleaner ways of doing it? – Kevin Krammer Oct 23 '16 at 09:10
0

Doing the following from a suggestion in discussion here solves the issue & gets a valid object to the QuickItem qml file

QQuickItem *myItem = engine.rootObjects()[0]->findChild<QQuickItem *>("myQuickItem");
Community
  • 1
  • 1
TheWaterProgrammer
  • 7,055
  • 12
  • 70
  • 159