Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Exposing C++ backend to QML
Forum Updated to NodeBB v4.3 + New Features

Exposing C++ backend to QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 3 Posters 3.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Marek
    wrote on last edited by
    #1

    Hi

    I can see two methods: qmlRegisterType and setContextProperty
    Is it possible to register backend.h in main.cpp which then will be exposed in main.qml

    import io.qt.examples.backend 1.0
    
    BackEnd {
            id: backend
        }
    

    And then if I create "QList<QObject*> dataList" of some sort in backend.cpp or its child classes I can use this as a model for example for Repeater somewhere in qml files eg. like this:

    Repeater {
        model: backend.someClass.dataList
    

    The idea is to have single "entry point" from QML to C++ classes

    Will this work?

    Best Regards
    Marek

    M 1 Reply Last reply
    0
    • M Marek

      Hi

      I can see two methods: qmlRegisterType and setContextProperty
      Is it possible to register backend.h in main.cpp which then will be exposed in main.qml

      import io.qt.examples.backend 1.0
      
      BackEnd {
              id: backend
          }
      

      And then if I create "QList<QObject*> dataList" of some sort in backend.cpp or its child classes I can use this as a model for example for Repeater somewhere in qml files eg. like this:

      Repeater {
          model: backend.someClass.dataList
      

      The idea is to have single "entry point" from QML to C++ classes

      Will this work?

      Best Regards
      Marek

      M Offline
      M Offline
      Marek
      wrote on last edited by
      #2

      Well this will not work.

      Digging deeper, I would like some clarify this:
      I have created subclassed QAbstractListModel based on this Sailfish nice example
      If I register this model:

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

      I can't pass any arguments during registration - according to this: QML needs to be able to instantiate the type, calling it with only parent QObject.
      So if my model needs to get the data from C++ part of the application, eg. from xmlMgr that reads files from directory, it can't be exposed to QML with qmlRegisterType - am I get this right?

      In case model needs to get data from C++ part I need to use

      demoModel=new DemoModel(xmlMgr);
      demoModel->init();
      view.rootContext()->setContextProperty("demoModel", demoModel);
      

      Is this how it supposed to be, or am I missing something?

      Best Regards
      Marek

      E 1 Reply Last reply
      0
      • M Marek

        Well this will not work.

        Digging deeper, I would like some clarify this:
        I have created subclassed QAbstractListModel based on this Sailfish nice example
        If I register this model:

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

        I can't pass any arguments during registration - according to this: QML needs to be able to instantiate the type, calling it with only parent QObject.
        So if my model needs to get the data from C++ part of the application, eg. from xmlMgr that reads files from directory, it can't be exposed to QML with qmlRegisterType - am I get this right?

        In case model needs to get data from C++ part I need to use

        demoModel=new DemoModel(xmlMgr);
        demoModel->init();
        view.rootContext()->setContextProperty("demoModel", demoModel);
        

        Is this how it supposed to be, or am I missing something?

        Best Regards
        Marek

        E Offline
        E Offline
        Eeli K
        wrote on last edited by
        #3

        @Marek If you have one object which you have created in C++ you can expose that object to be used in QML with setContextProperty. If a model is based on QAbstractItemModel and can be used automatically in C++ views it should work automatically with QML views, too. So I think your last comment is correct - you need only setContextProperty for it to work.

        M 1 Reply Last reply
        0
        • E Eeli K

          @Marek If you have one object which you have created in C++ you can expose that object to be used in QML with setContextProperty. If a model is based on QAbstractItemModel and can be used automatically in C++ views it should work automatically with QML views, too. So I think your last comment is correct - you need only setContextProperty for it to work.

          M Offline
          M Offline
          Marek
          wrote on last edited by
          #4

          @Eeli-K Thanks for answer.
          I hoped someone will add something about qmlRegisterType used with models (first approach), because as I see it now... it pretty much useless for registering models

          Best Regards
          Marek

          1 Reply Last reply
          0
          • O Offline
            O Offline
            osmial
            wrote on last edited by
            #5

            Hi @Marek,

            you don't need to create any instances of DemoModel in your C++. qmlRegisterType is enough, but you also need somehow to trigger update of your model. In my case I've created Q_INVOKABLE void update(); method in my model's class implementation which is being called each time data in model should be refreshed.
            Of course don't forget to override:
            int rowCount(const QModelIndex &parent);
            QVariant data(const QModelIndex &index, int role);
            methods in your model implementation.
            Here you have great description of model-view-delegate concept: http://doc.qt.io/qt-5/model-view-programming.html

            M 1 Reply Last reply
            0
            • O osmial

              Hi @Marek,

              you don't need to create any instances of DemoModel in your C++. qmlRegisterType is enough, but you also need somehow to trigger update of your model. In my case I've created Q_INVOKABLE void update(); method in my model's class implementation which is being called each time data in model should be refreshed.
              Of course don't forget to override:
              int rowCount(const QModelIndex &parent);
              QVariant data(const QModelIndex &index, int role);
              methods in your model implementation.
              Here you have great description of model-view-delegate concept: http://doc.qt.io/qt-5/model-view-programming.html

              M Offline
              M Offline
              Marek
              wrote on last edited by
              #6

              Hi @osmial

              I don't create DemoModel instance in C++. I know it will be created by QML and I know about Q_INVOKABLE.
              Lets say you have some cpp class dataMgr - it reads data from external source like tcp socket.
              This Data is needed for DemoModel, and you have DemoModel defined in cpp.
              How do you call DemoModel Q_INVOKABLE void update() from QML if DemoMode does not know about dataMgr ?
              DemoModel is instantiated in QML without pointer to dataMgr and you cant access DataModel from cpp.

              I assume that your update() from DemoModel reads data from some source but this process is completely isolated from the rest of cpp part of application, right?

              Best Regards
              Marek

              1 Reply Last reply
              0
              • M Offline
                M Offline
                Marek
                wrote on last edited by
                #7

                I have ended up with such a solution:

                int main(int argc, char *argv[])
                {
                    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                    QGuiApplication app(argc, argv);
                
                    QQmlApplicationEngine engine;
                
                    BackEnd backend(&engine);
                
                    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
                    if (engine.rootObjects().isEmpty())
                        return -1;
                
                    backend.init();
                
                    return app.exec();
                }
                

                Backend contructor is before engine load so the models are defined in QML
                Backend init is after engine load to get rootObject, signals etc.

                Backend - C++ part of the application

                #include "backend.h"
                
                BackEnd::BackEnd(QQmlApplicationEngine *engine) {
                    this->engine=engine;
                
                    xmlMgr=new XmlMgr(this);
                    itemModel=new ItemModel(this);
                
                    xmlMgr->init();
                    itemModel->loadData(xmlMgr);
                
                    context = engine->rootContext();
                    context->setContextProperty("ItemModel",itemModel);
                }
                void BackEnd::init() {
                
                    rootObject=engine->rootObjects().first();
                
                    connect(rootObject,SIGNAL(itemClicked(int)),this,SLOT(itemClicked(int)));
                }
                
                void BackEnd::itemClicked(int item_id) {
                    qDebug()<<"BackEnd::itemClicked item_id:"<<item_id;
                    int catalog_id=itemModel->getCatalogId(item_id);
                    if(catalog_id)
                        itemModel->setSelectedCatalog(catalog_id);
                }
                

                QML part

                ApplicationWindow {
                    visible: true
                    width: 640
                    height: 480
                    title: qsTr("Hello World")
                
                    signal itemClicked(int value)
                
                    header: Header {
                        height: 60;
                        width: parent.width
                    }
                    SwipeView {
                        id: swipeView
                        anchors.fill: parent
                
                        Page1 {
                
                        }
                        Page {
                            MainItem2 {
                                id: mainItem
                                visible: true
                            }
                         }
                     }
                }
                

                This works well for me.

                Best Regards
                Marek

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved