How to set a pure C++ object instance in a QQuickItem



  • Hi Guys.....I have QtApp & a pure C++ library. The C++ library exposes a one simple class called MyCppLibApiClass. The QtApp has a class which is embedded on main.qml. Following is the class:

    //MyQuickItem.h
    class MyQuickItem : public QQuickItem {
      MyQuickItem();
      SetCppObject(MyCppLibApiClass cppObject);
      MyCppLibApiClass m_cppObject;
    }
    

    Following the qml code for the quick item:

    //MainPage.qml
    import MyQuickItem 1.0
    
    MyQuickItem {
      id: myQuickItemID
      visible: true
      objectName: "myQuickItem"
    }
    

    Following is my main.cpp showing I load the qml item:

    //main.cpp
    qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    return app.exec();
    

    MyQuickItem needs access to MyCppLibApiClass instance. How do a I get a valid instance to MyQuickItem in main.cpp & call SetCppObject() on it ? I need to set an object of MyCppLibApiClass as member in MyQuickItem. I can do this using a setter method like SetCppObject. But, first of all I need to get a valid instance to MyQuickItem. So How to get access to MyQuickItem in main.cpp ?

    I have searched quite a lot before asking this question. I read through this link. But it describes how to set properties with only Qt types like QString & others.Appreciate suggestions to this..


  • Lifetime Qt Champion

    Hi,

    The code sample uses setPropertyas an example of method to call. You have the object at hand so call the methods you need on it.


  • Moderators

    @Nelson_Piquet You can also instantiate the MyCppLibApiClass in main.cpp then set it as a context property which will then be accessible from MyQuickItem in QML.
    Something like

    qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
    
    MyCppLibApiClass myClass;
    
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    engine.rootContext()->setContextProperty("myObj", &myClass); // Access myObj from QML
    
    return app.exec();
    

    More info here:
    http://doc.qt.io/qt-5/qtqml-cppintegration-contextproperties.html



  • @p3c0 @SGaist Thanks a lot for your attention. p3c0's answer suggests how to make MyCppLibApiClass recognisable on qml side. but, I cannot take this approach because this requires to make MyCppLibApiClass inherited by QObject if I am correct. MyCppLibApiClass comes from a pure C++ library & I cannot afford to introduce Qt into it. But My primary question is slightly different here. My question is: How to get a valid instance of MyQuickItem & call SetCppObject which accepts a pure Cpp obejct i.e. MyCppLibApiClass ? I have updated my question & sample code in the question to make it clearer


  • Moderators

    @Nelson_Piquet So as said earlier in the last post use findChild to get access to QML instance on C++ side. Now once you get this object call the SetCppObject function and pass cppObject to it.



  • @p3c0 I found that just doing a findChild does not give me access to SetCppObject. Looks like I have to cast it to MyQuickItem to get access to SetCppObject. Following compiles:

    QQuickView view;
    view.setSource(QUrl::fromLocalFile("main.qml"));
    QObject *object = view.rootObject();
    QObject *rect = object->findChild<QObject*>("MyQuickItem");
    MyQuickItem* quickItemObj = qobject_cast<MyQuickItem*>(rect);
    quickItemObj->SetCppObject(theCppObject);
    

    But qobject_cast returns me a null pointer. Q_OBJECT macro is included in MyQuickItem

    class MyQuickItem : public QQuickItem {
      Q_OBJECT
    public:
      MyQuickItem();
    }
    

    Should I do something in MyQuickItem class to get a valid pointer to MyQuickItem ? Or pls correct me if I am going wrong here


  • Moderators

    @Nelson_Piquet The object name that findChild accepts is case sensitive. I see a mismatch between this and your first post. ie. myQuickItem and MyQuickItem are totally different.

    But qobject_cast returns me a null pointer.

    Probably because the object was not found at first.



  • @p3c0 Thanks for point that out. I corrected the id. Also, the main.qml path I inputted was not the full path. It needs to be like so: qrc:/qml/main.qml. After applying a qobject_cast & I get a pointer to MyQuickItem.

    But when I try to access SetCppObject, it crashes reporting an error which says : QQuickView does not support using windows as a root item. If you wish to create your root window from QML, consider using QQmlApplicationEngine instead. But its a separate issue. I will read a little & put a separate question for that. Thanks a lot for helping until here.


  • Lifetime Qt Champion

    Maybe a silly question but do you really need a QQuickItem based wrapper ? Wouldn't a simple QObject wrapper do the work ?


  • Moderators

    @Nelson_Piquet As the error says QQuickView can only load root element of QML types that inherits Item whereas QQmlApplicationEngine loads root elements Window and ApplicationWindow.



  • @SGaist I really need a QQuickItem based wrapper. it is embedded in qml. I am not sure of how to make it work as a QObject wrapper. but, now I've reached a point with all the help where I am able to retrieve the object of MyQuickItem. But now, MyQuickItem's constructor gets called twice which is not what I need.......aahh !! Following is my main.cpp

    int main(int argc, char *argv[]) {
    
      QQmlApplicationEngine engine;
      qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
      QQuickView view;
      //Mainpage.qml is where MyQuickItem is located. Its sort of a child page of main.qml 
      view.setSource(QUrl(QStringLiteral("qrc:/qml/pages/MainPage.qml")));
      QObject *object = view.rootObject();
      QObject *rect = object->findChild<QObject*>("myQuickItem"); //pls note that myQuickItem is the object name
      MyQuickItem* quickItem = qobject_cast<MyQuickItem*>(rect);
      quickItem->SetCppObject(theCppObject);
      engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
      return app.exec();
    }
    

    My doubt is that view.setSource might need to be avoided but not sure how


  • Moderators

    @Nelson_Piquet There is no need to load 2 QML files separetely. This is going to create 2 windows and thus complicate. Just load your main QML using QQuickView or QQmlApplicationEngine and from there load other QML files.



  • @p3c0 What should I change in my main.cpp to avoid loading the files twice ? If I dont call view.setSource, I will not get hold of the child object. If dont call engine.load, I cannot load my main.qml. How should I change my main.cpp. Since this question is a separate issue, I have posted a new question in this forum here



  • @p3c0 @SGaist No need to answer the other question I posted. I got it working. Thanks a lot guys. Thanks a many !!!


  • Lifetime Qt Champion

    About the QObject wrapper, unless I misunderstood, you only want to act on your MyCppLibApiClass and not paint anything related to it thus the QObject wrapper can be used without any dependency on a visual element.



  • @SGaist understood. thanks


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.