This is a text-only version of the following page on https://raymii.org:
---
Title : QT / QML Signals and Slots with C++
Author : Remy van Elst
Date : 25-02-2021
URL : https://raymii.org/s/snippets/Cpp_QT_QML_Signals_and_Slots.html
Format : Markdown/HTML
---
QT has an Observer mechanism built in, which they call '[Signals and Slots](https://web.archive.org/web/20210210180603/https://
doc.qt.io/qt-5/signalsandslots.html)'. It allows objects to communicate with each other without having to have knowledge of eit
her ones internals. By inheriting from `QObject` and defining a few `Q_PROPERTY` macro's, the QT Meta Object Compiler (`moc`) d
oes all the hard work for you.
Inside a C++ class this all works handy dandy and is reasonable easy to follow, but when using QML it requires a bit more work.
This small example shows you how to bind QML and C++ together using signals and slots, in QT 5.12.
Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics.
Please, if you found this content useful, consider a small donation using any of the options below:
://leafnode.nl">I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go che
ck it out!
Consider sponsoring me on Github. It means the world to
me if you show your appreciation and you'll help pay the server costs.
ode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60
days.
Below a screenshot of the application. It's nothing more than a simple counter that
increments with a button or is set via a text input field, but it is enough to get
you started.
![screenshot][1]
Because this signal/slot construction is mostly string based, you cannot use the refactoring
tools provided by your IDE. If your method is based on `value` and you want to change
`value` to, lets say, `something`, you need to change the `Q_PROPERTY`, the QML usage
and bindings and all the regular C++ code. Not very obvious if you're not familiar with
how QT signals and slots and QML work.
For fun I compiled this example application to Webassembly as well. You can
[run it here][5], or at the bottom of this page it's embedded as an `iframe`.
### Summary
Because this is a small snippet, it lacks the explanation and depth you normally get from
my articles. Some code comments are provided, but the QT documentation is recommended reading
in this case:
- [Signals and slots][2]
- [Interaction with QML and C++][4]
It's explained there very extensive. That is also why I wrote up this summary,
due to all the comprehensive documentation, it's hard to get started with something small.
My example code has a C++ class named `Counter`, with one private `long long` named `m_Value`.
In the QML file I want to use this class and its methods, including the QT Signal/Slot.
The class must inherit from `QObject` and you must place the `Q_OBJECT` macro in the header:
class Counter : public QObject
{
Q_OBJECT
[...]
The methods for setting and getting the value are as you'd expect:
long long value() const { return m_Value; };
[...]
void Counter::setValue(long long value) {
if (value == m_Value)
return;
m_Value = value;
emit valueChanged(value);
}
In the above method you see the `emit` keyword. That's a blank define, for clarity. The
function `valueChanged()` is called. This is our `signal`, as in the header file:
signals:
void valueChanged(long long newValue);
The `setValue()` method is our `slot`:
public slots:
void setValue(long long value);
These are accessible to QML by this `Q_PROPERTY` line:
Q_PROPERTY(long long value READ value WRITE setValue NOTIFY valueChanged)
You could also connect these up to things via `QObject::connect()` but that is
out of this snippets scope. That is for when you use the signaling inside C++.
These lines in `main.cpp` is also required, it adds your class to QML so to say:
QQmlApplicationEngine engine;
Counter myCounter;
QQmlContext *context = engine.rootContext();
context->setContextProperty("MyCounter", &myCounter);
After this you can access `MyCounter` inside of QML as if it was a
regular C++ class. FOr example, to call the `Counter::value()` method:
Text {
text: "Counter: " + MyCounter.value + "."
}
Or the `Counter::setValue()` method:
Button {
text: qsTr("Set counter to 10")
// C++ method Counter::setValue(long long), bound via Q_PROPERTY
onClicked: MyCounter.setValue(10)
}
Due to the magic of the `moc` and the extra code it generates via `Q_PROPERTY`,
when you increment like in the below example, it knows which value to increment
and has generated correct operator overloads for it:
Button {
text: qsTr("Increase Counter")
onClicked: ++MyCounter.value
}
You can also receive the C++ signal right in QT. We've defined `valueChanged` as the
signal and via a `Connection` with `onValueChanged` (capitals matter here, prefix your
method with `on` and change the first character of your method name to a capital) you
can do things in QML. Like below, where I have a local variable that is incremented
each time the signal is received:
Text {
property int changeCount: 0
id: labelChanged
text: "Count has changed " + changeCount + " times."
// Receive the valueChanged NOTIFY
Connections {
target: MyCounter
onValueChanged: {
++labelChanged.changeCount
}
}
}
For a bi-directional binding example, look at the last `TextInput` in QML. It shows the current
value of the C++ class, updates when the value is updated and when you enter a number,
it updates the C++ class.
### Example code
Create a project folder and place all the files there under the filenames provided.
The project is also available on [github, here][3].
#### qmlcppsignalexample.pro
QT += quick
CONFIG += c++11
SOURCES += \
counter.cpp \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
counter.h
#### qml.qrc
main.qml
#### main.cpp
#include
#include
#include
#include
#include "counter.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Counter myCounter;
QQmlContext *context = engine.rootContext();
/* Below line makes myCounter object and methods available in QML as "MyCounter" */
context->setContextProperty("MyCounter", &myCounter);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
#### counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include
class Counter : public QObject
{
Q_OBJECT
Q_PROPERTY(long long value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit Counter(QObject *parent = nullptr);
long long value() const { return m_Value; };
public slots:
void setValue(long long value);
signals:
void valueChanged(long long newValue);
private:
long long m_Value {0} ;
};
#endif // COUNTER_H
#### counter.cpp
#include "counter.h"
Counter::Counter(QObject* parent) : QObject(parent)
{
}
void Counter::setValue(long long value) {
if (value == m_Value)
return;
m_Value = value;
emit valueChanged(value);
}
#### main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Controls 2.11
Window {
width: 640
height: 480
visible: true
title: qsTr("QML Signals and slots example - Raymii.org")
MenuBar {
width: parent.width
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
Column {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 20
Text {
id: info
width: parent.width * 0.9
wrapMode: Text.WordWrap
text: "QML / C++ binding via signals and slots example program, by Raymii.org. License: GNU GPLv3"
}
Text {
id: labelCount
// C++ method Counter::value(). Bound via Q_PROPERTY, updates automatically on change
text: "Counter: " + MyCounter.value + "."
}
Text {
property int changeCount: 0
id: labelChanged
text: "Count has changed " + changeCount + " times."
// Receive the valueChanged NOTIFY
Connections {
target: MyCounter
onValueChanged: {
++labelChanged.changeCount
}
}
}
Row {
spacing: 20
Button {
text: qsTr("Increase Counter")
onClicked: ++MyCounter.value
}
Button {
text: qsTr("Set counter to 10")
// C++ method Counter::setValue(long long), bound via Q_PROPERTY
onClicked: MyCounter.setValue(10)
}
Button {
text: qsTr("Reset")
onClicked: {
// C++ method Counter::setValue(long long), bound via Q_PROPERTY
MyCounter.setValue(0)
}
}
}
Row {
spacing: 20
Text {
id: setText
text: qsTr("Enter counter value: ")
}
Rectangle {
width: setText.width
height: setText.height
border.width: 1
border.color: "black"
TextInput {
id: counterInput
focus: true
text: MyCounter.value
}
}
// Bi-directional binding, entering a number in the textarea updates the
// C++ class, if the C++ class is updated, the textarea is updated as well.
Binding {
target: MyCounter
property: "value"
value: counterInput.text
}
}
}
}
### Build / Make
To create the above code, first create a build folder outside of the project:
cd /tmp
mkdir build-qmlexample
cd build-qmlexample
Run `qmake`, replace the path (`/home/remy/tmp/qt/qml_cpp_signal_example/`) to your project path:
qmake /home/remy/tmp/qt/qml_cpp_signal_example/qmlcppsignalexample.pro -spec linux-g++ CONFIG+=release && make qmake_all
This example uses `qmake`, but there should be no trouble using `cmake`. Not using anything fancy here.
When `qmake` has finished, you can run `make` to build the project:
make -j4
After a short while, the binary should be available:
$ file qml_cpp_signal_example
qml_cpp_signal_example: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64
/ld-linux-x86-64.so.2, BuildID[sha1]=f884f57b90ebf05b51551d42cef5ca3ee52037b4, for GNU/Linux 3.2.0, with debug_info, not stripp
ed
Run it from the commandline:
./qml_cpp_signal_example
### QT Webassembly Demo
For fun I [compiled][7] the example application to [webassembly][6]. Run it [here][5]
or, if it loads, an `iframe` below: