Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to connect a signal from C++ to a QML file in a QQuickWidget?
QtWS25 Last Chance

How to connect a signal from C++ to a QML file in a QQuickWidget?

Scheduled Pinned Locked Moved Solved General and Desktop
qquickwidgetc++ to qml
9 Posts 3 Posters 9.3k 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.
  • R Offline
    R Offline
    RolBri
    wrote on last edited by
    #1

    Hello,

    this is my first try to use something with QML.

    I have a C++ Qt GUI application with a normal MainWindow.
    There I have a QuickWidget which loads a QML file with the following code:

    import QtQuick 2.3
    import QtQuick.Controls.Styles 1.4
    import QtQuick.Extras 1.4
    
    Rectangle
    {
        color: "#201d1d"
        width: 600; height: 200
    
        function setvalue(value){ m1.value = value; }
    
        CircularGauge {
    
            transform: Rotation { origin.x: 0; origin.y: 0; angle: -90}
    
            id:m1
            width: 150
            height: 150
            x: 50
            y: 150
    
            style: CircularGaugeStyle {
                    minimumValueAngle: 0
                    maximumValueAngle: -120
            }
    
            minimumValue: 0
            maximumValue: 120
    }
    }
    

    The QML file is directly loaded using the QtCreator QQuickWidget properties.

    Now I would like to connect a function like the following to the CircularGauge in the QML file to set a new gauge value:

    void newValue(const double &value);
    connect(this, SIGNAL(newValue(double)), ui->QuickWidgetName, SLOT(setValue(double)));
    

    I googled the last hours, but I found no solution which worked :-(

    It would be really nice if you could help me with that.
    Thanks :-)

    1 Reply Last reply
    0
    • O Offline
      O Offline
      onek24
      wrote on last edited by onek24
      #2

      Example using the QQmlApplicationEngine :

      QQmlApplicationEngine engine;
      engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
      
      QObject *rootObject = qobject_cast<QObject*>(engine.rootObjects().first());
      
      QObject::connect(this, &MyClass::mySignal, [=](double value) {
          QMetaObject::invokeMethod(rootObject, "setValue", Q_ARG(double, value));
      });
      

      It's not tested but it should work. You can call QML functions using the invokeMethod function. rootObject is the QObject containing the function - in your case it is the rootObject(1st top-level object in qml). The connect is using the new sexy lambda expressions to call invokeMethod.

      1 Reply Last reply
      1
      • R Offline
        R Offline
        RolBri
        wrote on last edited by
        #3

        Thank you very much :-)

        I tried it, but it is not working.
        I used the following code with the QML file from above:

            QQmlApplicationEngine engine;
            engine.load(QUrl(QStringLiteral("qrc:/qml/QtQuickProgressBar.qml")));
        
            QObject *rootObject = qobject_cast<QObject*>(engine.rootObjects().first());
        
            QObject::connect(this, &MainWindow::setGauge, [=](double value) {
                QMetaObject::invokeMethod(rootObject, "setValue", Q_ARG(double, value));
            });
        
            emit setGauge(10.5);
        

        After the signal is fired I get the following error:
        QMetaObject::invokeMethod: No such method QtQuickProgressBar_QMLTYPE_41::setValue(double)
        What is wrong with the function function setvalue(value){ m1.value = value; }?

        As I said I am completely new to QML but as I understood you do not name a datatype in a function, right?

        Furthermore I have one big question-mark.
        I load my QML file in the GUI to a QQuickWidget and then I load it a second time into the QQmlApplicationEngine and then if the slot in the QML file is triggered in the Engine it is even visible in the GUI because the QML file is loaded twice?

        JKSHJ 1 Reply Last reply
        0
        • R RolBri

          Thank you very much :-)

          I tried it, but it is not working.
          I used the following code with the QML file from above:

              QQmlApplicationEngine engine;
              engine.load(QUrl(QStringLiteral("qrc:/qml/QtQuickProgressBar.qml")));
          
              QObject *rootObject = qobject_cast<QObject*>(engine.rootObjects().first());
          
              QObject::connect(this, &MainWindow::setGauge, [=](double value) {
                  QMetaObject::invokeMethod(rootObject, "setValue", Q_ARG(double, value));
              });
          
              emit setGauge(10.5);
          

          After the signal is fired I get the following error:
          QMetaObject::invokeMethod: No such method QtQuickProgressBar_QMLTYPE_41::setValue(double)
          What is wrong with the function function setvalue(value){ m1.value = value; }?

          As I said I am completely new to QML but as I understood you do not name a datatype in a function, right?

          Furthermore I have one big question-mark.
          I load my QML file in the GUI to a QQuickWidget and then I load it a second time into the QQmlApplicationEngine and then if the slot in the QML file is triggered in the Engine it is even visible in the GUI because the QML file is loaded twice?

          JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote on last edited by JKSH
          #4

          @onek24 said:

          It's not tested but it should work. You can call QML functions using the invokeMethod function. rootObject is the QObject containing the function - in your case it is the rootObject(1st top-level object in qml). The connect is using the new sexy lambda expressions to call invokeMethod.

          @RolBri said:

          QMetaObject::invokeMethod: No such method QtQuickProgressBar_QMLTYPE_41::setValue(double)
          What is wrong with the function function setvalue(value){ m1.value = value; }?

          Be aware of 2 things (both explained in http://doc.qt.io/qt-5/signalsandslots-syntaxes.html#connecting-c-objects-to-qml-objects ):

          1. To connect C++ and QML, you need to use the old string-based connection. The new sexy lambda expression won't work.
          2. C++ sees the parameter type as QVariant, not double.

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          O 1 Reply Last reply
          1
          • R Offline
            R Offline
            RolBri
            wrote on last edited by
            #5

            Thanks,

            I changed it to QVariant and the "old" connection format.
            Now I do not get any errors, but I can not see anything changing in the GUI.

            I guess it is not enough to load the same QML file to the QQmlApplicationEngine and the QQuickWidget.
            So how can I tell my QQuickWidget to show the object I created with the QQmlApplicationEngine?

            JKSHJ 1 Reply Last reply
            0
            • R RolBri

              Thanks,

              I changed it to QVariant and the "old" connection format.
              Now I do not get any errors, but I can not see anything changing in the GUI.

              I guess it is not enough to load the same QML file to the QQmlApplicationEngine and the QQuickWidget.
              So how can I tell my QQuickWidget to show the object I created with the QQmlApplicationEngine?

              JKSHJ Offline
              JKSHJ Offline
              JKSH
              Moderators
              wrote on last edited by JKSH
              #6

              @RolBri said:

              I guess it is not enough to load the same QML file to the QQmlApplicationEngine and the QQuickWidget.

              Correct. This will give you 2 separate QML objects. It's a bit like creating 2 separate MainWindows.

              So how can I tell my QQuickWidget to show the object I created with the QQmlApplicationEngine?

              You can't. QQuickWidget uses its own internal engine.

              Connect to the QQuickWidget's root object instead (see the link I gave you), and don't create a second QQmlEngine.

              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

              1 Reply Last reply
              1
              • JKSHJ JKSH

                @onek24 said:

                It's not tested but it should work. You can call QML functions using the invokeMethod function. rootObject is the QObject containing the function - in your case it is the rootObject(1st top-level object in qml). The connect is using the new sexy lambda expressions to call invokeMethod.

                @RolBri said:

                QMetaObject::invokeMethod: No such method QtQuickProgressBar_QMLTYPE_41::setValue(double)
                What is wrong with the function function setvalue(value){ m1.value = value; }?

                Be aware of 2 things (both explained in http://doc.qt.io/qt-5/signalsandslots-syntaxes.html#connecting-c-objects-to-qml-objects ):

                1. To connect C++ and QML, you need to use the old string-based connection. The new sexy lambda expression won't work.
                2. C++ sees the parameter type as QVariant, not double.
                O Offline
                O Offline
                onek24
                wrote on last edited by onek24
                #7

                @JKSH said:

                Be aware of 2 things (both explained in http://doc.qt.io/qt-5/signalsandslots-syntaxes.html#connecting-c-objects-to-qml-objects ):

                1. To connect C++ and QML, you need to use the old string-based connection. The new sexy lambda expression won't work.
                2. C++ sees the parameter type as QVariant, not double.

                Huh that's strange. It definitely works in my cases using the new sexy lambda expression.

                Also from the QMetaObject::invokeMethod docs i took the following example:

                QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                                          Q_RETURN_ARG(QString, retVal),
                                          Q_ARG(QString, "sqrt"),
                                          Q_ARG(int, 42),
                                          Q_ARG(double, 9.7));
                

                I was using QVariant but after i read this code-snippet in the docs i changed it in my example code which i wrote some posts ealier.

                JKSHJ 1 Reply Last reply
                0
                • O onek24

                  @JKSH said:

                  Be aware of 2 things (both explained in http://doc.qt.io/qt-5/signalsandslots-syntaxes.html#connecting-c-objects-to-qml-objects ):

                  1. To connect C++ and QML, you need to use the old string-based connection. The new sexy lambda expression won't work.
                  2. C++ sees the parameter type as QVariant, not double.

                  Huh that's strange. It definitely works in my cases using the new sexy lambda expression.

                  Also from the QMetaObject::invokeMethod docs i took the following example:

                  QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                                            Q_RETURN_ARG(QString, retVal),
                                            Q_ARG(QString, "sqrt"),
                                            Q_ARG(int, 42),
                                            Q_ARG(double, 9.7));
                  

                  I was using QVariant but after i read this code-snippet in the docs i changed it in my example code which i wrote some posts ealier.

                  JKSHJ Offline
                  JKSHJ Offline
                  JKSH
                  Moderators
                  wrote on last edited by
                  #8

                  @onek24 said:

                  Huh that's strange. It definitely works in my cases using the new sexy lambda expression.

                  Argh, my bad... I got mixed up between your lambda and the QML function. You're right, the lambda is fine, because you're not connecting directly to QML.

                  Also from the QMetaObject::invokeMethod docs i took the following example:

                  QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                                            Q_RETURN_ARG(QString, retVal),
                                            Q_ARG(QString, "sqrt"),
                                            Q_ARG(int, 42),
                                            Q_ARG(double, 9.7));
                  

                  That works if the object has a C++ function with the signature like this: QString compute (const QString& value1, int value2, double value3)

                  However, all QML functions are JavaScript functions, and JavaScript functions take var parameters. var in JavaScript/QML maps to QVariant in C++.

                  • QML declaration: function setvalue(value)
                  • C++ equivalent: void setValue(const QVariant& value)

                  So, you must use QVariant in the Q_ARG() macro.

                  Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                  1 Reply Last reply
                  1
                  • R Offline
                    R Offline
                    RolBri
                    wrote on last edited by
                    #9

                    Thank you very much, now it works fine :-)

                    Here is the solution:

                        ui->gauge_quick->setSource(QUrl(QStringLiteral("qrc:/qml/QtQuickProgressBar.qml")));
                        ui->gauge_quick->show();
                        auto rootObject = ui->gauge_quick->rootObject();
                    
                        connect(this, SIGNAL(setGauge(QVariant)), rootObject, SLOT(setvalue(QVariant)));
                    
                        emit setGauge(15.5);
                    
                    1 Reply Last reply
                    1

                    • Login

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