How to connect a button signal in QML with C++



  • Hello people,

    In QML I have defined "CustomButton.qml" :

    @Button {
    id: myButton;
    text: "btnTxt";
    property string nodeName
    property string objectName
    property string caption

    signal buttonClick(string buttonId);
    
    onButtonClick: {
        buttonClick(myButton.objectName);
    }
    
    MouseArea {
        id: clickArea
        anchors.fill: parent
        onClicked:
        {
            myButton.buttonClick(myButton.objectName);
        }
    

    }
    }@

    In main.cpp I have:

    @int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    // Step 1: get access to the root object and main Content Item
        QObject *rootObject = engine.rootObjects().first();
    
       // connect signals and slots
        MyClass myClass;
        QObject::connect(rootObject, SIGNAL(buttonClick(QString)),
                         &myClass, SLOT(cppSlot(QString)));
    
    return app.exec();
    

    }@

    MyClass::cppSlot only prints the QString it receives.
    In my case it doesn't print it because it cant find the signal in the root object; i.e. there is no buttonClick() signal in rootObject (ie mainWindow item in QML). The signal is inside the button, and my button is in the rootObject, where my pointer is pointing in C++.
    All buttons should be able to connect to one SLOT in C++, where they shall pass their ID as a string.
    Does anyone know *how do I send the buttonClick() signal to C++, and connect it with the respective SLOT? *

    Thanks a ton for your help :))))


  • Moderators

    Hi,

    Few points:

    1. Have you made sure rootObjects().first() is returning you the Button reference ?
    2. Why have you used MouseArea in Button ? You can directly use onClicked signal handler since it has clicked() signal.


  • Hi p3c0,

    The rootObject points to the mainWindow of the application. The buttons are dynamically generated from an XML file, hence they have no id, ie cant be accessed thru pointers.
    My question is there an elegant way to connect the buttonClick() signal with the C++? Or should I not define my button in QML, but rather as a C++ class and use the Q_PROPERTY notifications or something like that.

    I thought maybe its possible from QML, but with pointers it doesnt make sense, as there will be many many buttons which will get generated, and they should all connect to one slot.

    Depending on the buttonClicked(Qstring) different functions will be called. But first I need to get that signal from QML button to C++.



  • Hi,

    Not sure if this is elegant enugh for you. Here's an example on how to connect C++ class to QML and how to send signals in both directions.

    main.cpp

    @
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <myclass.h>

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);

    MyClass myClass;
    
    QQmlApplicationEngine engine;
    
    //Make my class available in QML.
    engine.rootContext()->setContextProperty("myClass", &myClass);
    
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
    
    return app.exec();
    

    }
    @

    MyClass header:

    @
    #ifndef MYCLASS_H
    #define MYCLASS_H

    #include <QObject>
    #include <QDebug>

    class MyClass : public QObject
    {
    Q_OBJECT
    public:
    explicit MyClass(QObject *parent = 0);

    signals:
    void someSignal(QString str);

    public slots:
    void someSlot(QString str);
    };

    #endif // MYCLASS_H
    @

    My class cpp:

    @
    #include "myclass.h"

    MyClass::MyClass(QObject *parent) :
    QObject(parent)
    {
    }

    void MyClass::someSlot(QString str) {
    qDebug() << "someSlot received string: " << str;
    someSignal("I received your button click. You sent me " + str);
    }
    @

    CustomButton.qml:

    @
    import QtQuick 2.0
    import QtQuick.Controls 1.2

    Button {
    id: myButton;
    text: "btnTxt";
    property string objectName: "some value"

    signal someSignalName(string buttonId);
    
    MouseArea {
        id: clickArea
        anchors.fill: parent
        onClicked:
        {
            console.log("Button clicked")
            someSignalName(parent.objectName);
        }
    }
    

    }
    @

    And main.qml

    @
    import QtQuick 2.2
    import QtQuick.Window 2.1

    Window {
    width: 360
    height: 360
    color: "white"
    visible: true

    Connections {
        target: myClass
    
        onSomeSignal: {
            console.log("Received signal from my class with string: " + str)
        }
    }
    
    Rectangle {
        color: "white"
        anchors.fill: parent
    
    }
    
    CustomButton {
        id: btn
        width: 100
        height: 50
    
        onSomeSignalName: {
            console.log("Clicked received from CustomButton.qml, calling slot in C++")
            console.log("Received btnid: " + buttonId)
            myClass.someSlot(buttonId)
        }
    }
    

    }
    @


  • Moderators

    Yes there is a way.
    But can you tell what does this print in reference to your code?
    @
    QObject *rootObject = engine.rootObjects().first();
    qDebug() << rootObject;
    @



  • p3c0 that one prints:
    ApplicationWindow_QMLTYPE_51_QML_55(0x101f2a3f0)

    Furthermore I can read go on and point to its child: mainContentItem. MainContentItem has a signal qmlSignal(QString), and therefore it works. But how do I make it work with buttons? Hmmm

    @ // Step 1: get access to the root object
    QObject *rootObject = engine.rootObjects().first();
    qDebug() <<"My root obj: "<< rootObject;
    QObject qmlObject = rootObject->findChild<QObject> ("mainContentItem");

        MyClass myClass;
        QObject::connect(qmlObject, SIGNAL(qmlSignal(QString)), &myClass, SLOT(cppSlot(QString)));
    

    @


  • Moderators

    In the same way find Button with objectName.
    @
    QObject item = engine.rootObjects().first()->findChild<QObject>("objButton"); //objButton = Button's objectName
    @

    Also why Mousearea for Button ?



  • p3c0, the original code is:

    @Button {
    id: myButton;
    text: "btnTxt";
    property string objectName
    property string caption

    signal buttonClick(string buttonId);
    
    onButtonClick: {
        console.log("Button "+ myButton.objectName +" is clicked!")
    }
    
    MouseArea {
        id: clickArea
        anchors.fill: parent
        onClicked:
        {
            myButton.buttonClick(myButton.objectName);
        }
    }
    
    style: ButtonStyle {
                            background:
    
                                Rectangle {
                                id: styleRect
                                color: clickArea.pressed ?  "#336699" : "#0099FF"
                                radius: 2
                                }
                       }
    

    }@

    I put mouseArea for styling purposes, as I want to change the color when the button is pressed. I tried not to use it, but I am making a mistake somewhere and it does not worked as supposed to. You have any other suggestions, I would be glad to know better approach.

    Thanks


  • Moderators

    Alright. Just got confused. Can you try the following if it works ? Some modifications in your code.

    MyWindow.qml
    @
    Window {
    width: 200
    height: 200
    visible: true

    CustomButton {
        id: custom
        objectName: "mybutton"
    }
    

    }
    @

    CustomButton.qml
    @
    Button {
    id: myButton
    text: "btnText"

    signal mySignal(string str)
    
    MouseArea {
        id: clickArea
        anchors.fill: parent
        onClicked: mySignal(myButton.text)
    }
    
    style: ButtonStyle {
        background:
            Rectangle {
            id: styleRect
            color: clickArea.pressed ?  "green" : "red"
            radius: 2
        }
    }
    

    }
    @

    main.cpp
    @
    MyClass myClass; //assuming it has slot cppSlot(QString)
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///MyWindow.qml")));
    QObject but = engine.rootObjects().first()->findChild<QObject>("mybutton");
    qDebug() << but->objectName();
    QObject::connect(but,SIGNAL(mySignal(QString)),&myClass,SLOT(cppSlot(QString)));
    @

    After clicking the button, the slot in MyClass should print "btnText"


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.