Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Connecting C++ signal to QML slot



  • Hi,
    I am new to qt and want to pass a simple signal from a c++ widget to qml. I followed the structure in this document with a few changes. . The code complies but nothing shows up due to this error:
    QObject::connect: No such slot QQuickItem::qmlSlot(QVariant) in ../qmltest/mainwindow.cpp:15
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    qmltest.pro:

    QT += core gui qml quickwidgets
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    CONFIG += c++11
    ...

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    mainwindow.cpp:
    MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    {
    auto cppObj = new Widget();
    auto quickWidget = new QQuickWidget(QUrl("qrc:/main.qml"));
    auto qmlObj = quickWidget->rootObject();

    // Connect C++ signal to QML slot
    connect(cppObj, SIGNAL(cppSignal(QVariant)),
            qmlObj, SLOT(qmlSlot(QVariant)));
    

    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    mainwindow.h:
    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    };
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    widget.cpp:

    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    {

    button = new QPushButton("Click Me!", this);
    connect(button, &QPushButton::clicked, [=] {
        emit cppSignal("hello");
    });
    

    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    widget.h:

    class Widget : public QWidget
    {
    Q_OBJECT
    QPushButton *button;
    signals:
    void cppSignal(const QVariant& sentMsg) const;

    public:
    Widget(QWidget *parent = 0);
    ~Widget();
    };
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    main.qml:
    import QtQuick 2.15
    import QtQuick.Controls 2.15

    Item {
    Rectangle {
    width: 100; height: 100
    function qmlSlot(receivedMsg) {
    console.log("QML received: " + receivedMsg)
    }

    }
    

    }

    Can anyone help me with this? I also used MetaObject::invokeMethod(qmlObj, "qmlSlot"); same error.
    Note that in this project I designed a keyboard by QWidgets to type and want to pass the pushed keys to the qml which is a chat GUI in this work. So I have to use qquickwidgets to show both keyboard and chat GUI in the same window.


  • Moderators

    @Mary_M
    you try to connect to a method of the rootItem(). But in your qml file the object with the desired method is not the root item. It has a parent Item.

    Its probably anyway easier to do the connection inside QML and not in C++.



  • @raven-worx Thank you! I tried with the root item, no error but the text doesn't show up! Also, I need the signal to be emitted from C++.



  • @Mary_M It is recommended to make the connection in qml:

    *.cpp

    auto cppObj = new Widget();
    auto quickWidget = new QQuickWidget();
    quickWidget->rootContext()->setContextProperty("cppObj", cppObj);
    quickWidget->setSource(QUrl("qrc:/main.qml"));
    

    main.qml

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    
    Item {
        Rectangle {
            width: 100; height: 100
        }
        Connections{
            target: cppObj
            function onCppSignal(receivedMsg){
                console.log("QML received: " + receivedMsg)
            }
        }
    }
    


  • Try something like this:

    Q_INVOKABLE void triggerEvent(QString text) {
     emit signalEvent(text);
    }
    Person() {
     startTimer(1000);
    }
    void timerEvent(QTimerEvent *e) {
     QString text = "Hello";
     triggerEvent(text);
    }
    
    signals: 
    void signalEvent(QString text);
    
    //In qml:
    
    id: myQmlObject
    onSignalEvent: {
     console.log(" Message " + text);
    }
    


  • @eyllanesc Thank you so much! but when I use connections this is the error:
    QObject::connect: Cannot connect Widget::cppSignal(QVariant) to (nullptr)::qmlSlot(QVariant)

    I also tried this one but still the same:
    Item {
    Rectangle {
    id: rect
    width: 100; height: 100
    Text{id:myText} }
    Connections{
    target: cppObj
    function onCppSignal(receivedMsg){
    MyText.text = receivedMsg;
    }
    }
    }



  • @GabrielRR Thanks! but how can I use this in widget.cpp not in mainwindow?



  • @Mary_M Have you deleted your C++ connection attempt? That error message is not from QML but from C++, also remove build folder and compile.



  • @eyllanesc You are right! I deleted connect in mainwindow now and built it again. No error now but no output either! Only empty window showed up. At the end I used Qframe and gridline to add button and rect alongside. Many thanks!



  • @Mary_M If your issue is solved please don't forget to mark the post as such!


Log in to reply