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. How to connect a button signal in QML with C++
Forum Updated to NodeBB v4.3 + New Features

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

Scheduled Pinned Locked Moved QML and Qt Quick
9 Posts 3 Posters 12.6k Views 1 Watching
  • 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.
  • M Offline
    M Offline
    mshefiti
    wrote on last edited by
    #1

    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 :))))

    1 Reply Last reply
    0
    • p3c0P Offline
      p3c0P Offline
      p3c0
      Moderators
      wrote on last edited by
      #2

      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.

      157

      1 Reply Last reply
      0
      • M Offline
        M Offline
        mshefiti
        wrote on last edited by
        #3

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

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

          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)
              }
          }
          

          }
          @

          1 Reply Last reply
          0
          • p3c0P Offline
            p3c0P Offline
            p3c0
            Moderators
            wrote on last edited by
            #5

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

            157

            1 Reply Last reply
            0
            • M Offline
              M Offline
              mshefiti
              wrote on last edited by
              #6

              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)));
              

              @

              1 Reply Last reply
              0
              • p3c0P Offline
                p3c0P Offline
                p3c0
                Moderators
                wrote on last edited by
                #7

                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 ?

                157

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  mshefiti
                  wrote on last edited by
                  #8

                  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

                  1 Reply Last reply
                  0
                  • p3c0P Offline
                    p3c0P Offline
                    p3c0
                    Moderators
                    wrote on last edited by
                    #9

                    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"

                    157

                    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