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 28 Oct 2015, 12:59 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 28 Oct 2015, 13:54 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 28 Oct 2015, 14:45 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?

        J 1 Reply Last reply 28 Oct 2015, 15:02
        0
        • R RolBri
          28 Oct 2015, 14:45

          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?

          J Offline
          J Offline
          JKSH
          Moderators
          wrote on 28 Oct 2015, 15:02 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 28 Oct 2015, 16:01
          1
          • R Offline
            R Offline
            RolBri
            wrote on 28 Oct 2015, 15:46 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?

            J 1 Reply Last reply 28 Oct 2015, 15:56
            0
            • R RolBri
              28 Oct 2015, 15:46

              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?

              J Offline
              J Offline
              JKSH
              Moderators
              wrote on 28 Oct 2015, 15:56 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
              • J JKSH
                28 Oct 2015, 15:02

                @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 28 Oct 2015, 16:01 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.

                J 1 Reply Last reply 28 Oct 2015, 16:30
                0
                • O onek24
                  28 Oct 2015, 16:01

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

                  J Offline
                  J Offline
                  JKSH
                  Moderators
                  wrote on 28 Oct 2015, 16:30 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 29 Oct 2015, 08:40 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

                    7/9

                    28 Oct 2015, 16:01

                    • Login

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