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. C++ singleton interfacing with QML
Forum Updated to NodeBB v4.3 + New Features

C++ singleton interfacing with QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qml c++ signalssingleton class
4 Posts 3 Posters 7.4k Views
  • 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.
  • S Offline
    S Offline
    sly110
    wrote on last edited by
    #1

    I have a new problem but still associated with interaction between C++ and QML.

    I have a C++ class instantiated in main.cpp. I want all QML files to be able to access properties, invokable functions and receive signals from this class. I also want other C++ classes to do the same. This is a main class which forms a framework for my app and has qml files being show in a stackview. Think QML window with embedded qml viewport. This is using a model/view arch.

    So I initially, with help, added this class to qml context and made connection in qml.
    See https://forum.qt.io/topic/77216/receiving-c-signal-in-qml/5

    This allowed me to get signals from the class but I was not able to get invokable functions to work without generating warnings in debugger console BUT they did work. But my QList model stopped working. Seemed as if QList was no longer registered with QML.

    So I went down the path of creating a singleton class which is really how this main class/frame should work. Only 1 instance.

    Now I can access invokable functions without warnings, still my model is broken BUT now the slots in qml don't work again. Driving me crazy.

    Any help please!!

    //your code here
    ```main.cpp
    //SLY HERE
    // Second, define the singleton type provider function (callback).
    static QObject *QmlMainSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine)
        Q_UNUSED(scriptEngine)
    
        QmlMain *qmlmain = new QmlMain();
        return qmlmain;
    }
    ...
        qmlRegisterSingletonType<QmlMain>("Main", 1, 0, "QmlMain", QmlMainSingletonProvider);
    
    ```main.qml
    import Main 1.0
    ...
        //slot for QmlMain
        Connections {
            target: QmlMain
    
               onBootStrapDone: {
                console.log("onBootStrapDone", QmlMain.KeyModel.target)
                QmlMain.cppNavSlot(QmlMain.KeyModel.target)
            }
    
            onKeyModelChanged:{  //only getting this after a click
                console.log("onKeyModelChanged", QmlMain.Title)
                console.log("onKeyModelChanged", QmlMain.Source)
    //            window.reloadModel =  true;
                drawer.close()
                titleLabel.text = QmlMain.Title
                stackView.replace(QmlMain.Source)
            }
        }
    ...
    //an invokable function in qmlmain.cpp
     text: QmlMain.mTr("#Help")
    

    //your code here

    E 1 Reply Last reply
    0
    • dheerendraD Offline
      dheerendraD Offline
      dheerendra
      Qt Champions 2022
      wrote on last edited by
      #2

      Looks like some mixup is happening. Slot in qml is not called means your qml main object did not emit appropriate signal. Can you confirm signal is generated from your QmlMain object ? How qlistmodel is related here. This confused me as well. May b u can split the question.

      Dheerendra
      @Community Service
      Certified Qt Specialist
      http://www.pthinks.com

      1 Reply Last reply
      2
      • S sly110

        I have a new problem but still associated with interaction between C++ and QML.

        I have a C++ class instantiated in main.cpp. I want all QML files to be able to access properties, invokable functions and receive signals from this class. I also want other C++ classes to do the same. This is a main class which forms a framework for my app and has qml files being show in a stackview. Think QML window with embedded qml viewport. This is using a model/view arch.

        So I initially, with help, added this class to qml context and made connection in qml.
        See https://forum.qt.io/topic/77216/receiving-c-signal-in-qml/5

        This allowed me to get signals from the class but I was not able to get invokable functions to work without generating warnings in debugger console BUT they did work. But my QList model stopped working. Seemed as if QList was no longer registered with QML.

        So I went down the path of creating a singleton class which is really how this main class/frame should work. Only 1 instance.

        Now I can access invokable functions without warnings, still my model is broken BUT now the slots in qml don't work again. Driving me crazy.

        Any help please!!

        //your code here
        ```main.cpp
        //SLY HERE
        // Second, define the singleton type provider function (callback).
        static QObject *QmlMainSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
        {
            Q_UNUSED(engine)
            Q_UNUSED(scriptEngine)
        
            QmlMain *qmlmain = new QmlMain();
            return qmlmain;
        }
        ...
            qmlRegisterSingletonType<QmlMain>("Main", 1, 0, "QmlMain", QmlMainSingletonProvider);
        
        ```main.qml
        import Main 1.0
        ...
            //slot for QmlMain
            Connections {
                target: QmlMain
        
                   onBootStrapDone: {
                    console.log("onBootStrapDone", QmlMain.KeyModel.target)
                    QmlMain.cppNavSlot(QmlMain.KeyModel.target)
                }
        
                onKeyModelChanged:{  //only getting this after a click
                    console.log("onKeyModelChanged", QmlMain.Title)
                    console.log("onKeyModelChanged", QmlMain.Source)
        //            window.reloadModel =  true;
                    drawer.close()
                    titleLabel.text = QmlMain.Title
                    stackView.replace(QmlMain.Source)
                }
            }
        ...
        //an invokable function in qmlmain.cpp
         text: QmlMain.mTr("#Help")
        

        //your code here

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

        @sly110 I also feel there are several things going on here and you should break it into several questions and give a bit more information. If you have problems with invokables and warnings, tell what they are, what did you do, what did you expect, what did you get etc.

        If you want to have one object, coded in C++, created in C++, and use it in both C++ and QML, you should write a normal QObject derived class, instantiate it in C++, set it as context property for QML and start the QML engine and the application. Here is part of my code:

            QQmlApplicationEngine* engine{new QQmlApplicationEngine()};
            QQmlContext* ctx{engine->rootContext()};
            Connection* conn{new Connection()};
            CameraController* camera{new CameraController(conn)};
            qmlRegisterUncreatableType<CameraController>("eu.vpsystems.software", 1, 0, "CameraController", "Not to be created as QML type");
            ctx->setContextProperty("connection", conn);
            ctx->setContextProperty("camera", camera);
            engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
            app->exec();
        

        I have no problems with signals or slots in both ways or C++ properties or Q_INVOKABLEs. I use qmlRegisterUncreatableType because that class has enums which I want to use in QML. I also use models/views where model is based on QStandardItemModel, created in C++, set as a context property and used in QML.

        I don't know what a Qt singleton type is used for, but probably it isn't the right solution here. The singleton object is created by the QML engine and as far as I can see it's not meant to be used in C++. (About singletons in general, though not necessarily this Qt singleton, google for "why singleton is bad".) If you want only one object, create just one object. If it's created in C++ it can be used in QML after it has been set as context property.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          sly110
          wrote on last edited by
          #4

          All,
          Yes I am sorry for the mix up . Late and frustrated.

          Anyway I did a lot of refactoring based on the feedback and appear to have one glaring problem. Previously, my KeyData class was being instantiated without me knowing it by QML. Now the attempt is to instantiate from C++. I have a drawer control in QML that is a bunch of nav buttons. The model for this is in C++ as a QList of *KeyData.
          So my drawer is now unpopulated and in the debug window the error is:
          QMetaProperty::read: Unable to handle unregistered datatype 'QQmlListProperty<KeyData>' for property 'QmlMain::KeyModel'. Previously that was not an issue. I think a complication at least for me is that key and Nav are defined as structures and I've had to prepend 'struct' everywhere they were used.

          struct Key
          {
              QString id;
              QString type;
              QString title;
              QString icon;
              QString target;
          };
          
          struct Nav
          {
              QString id;
              QString title;
              QString source;
              QList <Key> keys;
              QList <int> milestones;
          };
          

          In my main class header that is now a exposed to QML as a context property, I have:

            Q_PROPERTY  (QQmlListProperty<KeyData> KeyModel READ readKeyModel NOTIFY keyModelChanged)
          ...
              //model for model/view of keys
              void writeKeyModel();
              QQmlListProperty<KeyData> readKeyModel();
          
              QList<KeyData *> getKeyModel() const;
              void setKeyModel(const QList<KeyData *> &keyModel);
          ...
              QList<KeyData *> _keyModel;
          

          In my main class imlementation I have:

          QList<KeyData *> QmlMain::getKeyModel() const
          {
              return _keyModel;
          }
          
          void QmlMain::setKeyModel(const QList<KeyData *> &keyModel)
          {
              _keyModel = keyModel;
          }
          
          
           QQmlListProperty<KeyData>  QmlMain::readKeyModel()
          {
              return QQmlListProperty<KeyData>(this, _keyModel);
          
          }
          
          
          void QmlMain::writeKeyModel()
          {
              _keyModel.clear();
          
              Key key;
              foreach (key, this->_navRecord.keys) {
                    _keyModel.append(new KeyData(key.id, key.type, key.title, key.icon, key.target));
              }
          
              qDebug() << "setKeyModel";
          //    emit this->keyModelChanged();
          }
          

          In QML I have

              //nav drawer
              Drawer {
                  id: drawer
                  width: Math.min(window.width, window.height) / 3 * 2
                  height: window.height
                  background: Rectangle {  //add fill to drawer
                      anchors.fill: parent
                      color: "white"
                  }
                  ListView {
                      id: listView
                      currentIndex: -1
                      anchors.fill: parent
                      model: QML_MAIN.KeyModel     //c++ model
          

          Thank you for any help you are kind enough to provide

          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