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 captionsignal 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 :))))
-
Hi,
Few points:
- Have you made sure rootObjects().first() is returning you the Button reference ?
- 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.2Button {
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.1Window {
width: 360
height: 360
color: "white"
visible: trueConnections { 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) } }
}
@ -
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)));
@
-
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 captionsignal 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
-
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: trueCustomButton { 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"