This is a text-only version of the following page on https://raymii.org:
---
Title : Qt Property Macro (Q_PROPERTY with 95% less code)
Author : Remy van Elst
Date : 29-05-2024 22:00
URL : https://raymii.org/s/blog/Qt_Property_Macro_Q_PROPERTY_with_95_percent_less_code.html
Format : Markdown/HTML
---
![qt logo](/s/inc/img/Qt_logo_2016.png)
Adding [properties to QObject based classes](https://web.archive.org/web/20240529180113/https://doc.qt.io/qt-6/properties.html) is cumbersome. Although [the property system](https://web.archive.org/web/20240529180113/https://doc.qt.io/qt-6/properties.html) and [Signals and Slots](https://web.archive.org/web/20240529180002/https://doc.qt.io/qt-6/signalsandslots.html) are great to use, especially with QML, it takes a lot of boilerplate code to add such properties to a class, at least 15 to 20 lines for each property. I've cobbled up a macro that saves you about 95% of lines when using a `Q_PROPERTY`. (22 lines to 1 line).
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:
I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check 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.
You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!
### Adding a Q_PROPERTY
To add a [property to a QObject based class](https://web.archive.org/web/20240529180113/https://doc.qt.io/qt-6/properties.html),
you have to add the following items to the class:
- `Q_PROPERTY` statement
- Declaration of getter and setter methods
- Definition of getter and setter methods
- Value changed signal definition
- Member variable
Recent versions of Qt Creator have made this more efficient by auto-filling
the `Q_PROPERTY` statement and via a right-click you can now go
to `Refactor` then `Add missing Q_PROPERTY members`, but that is still
more work and more typing than using a macro that does it all for you.
With this macro, `QObject::connect` still works as you would expect just as
accessing the property from QML.
There also is the `MEMBER` Qt property type but that is still more boilerplate
than this because you still need to write the entire line including notify
signal and member variables.
### QObject Property Macro
This is the macro I've defined:
/* Macro to define Q_PROPERTY backed by a regular value
* QP_V = Q_Property, value (not reference) */
#define QP_V(Type, Name) \
private: \
Q_PROPERTY(Type Name READ Name WRITE set##Name NOTIFY Name##Changed FINAL) \
Type _##Name; \
public: \
Type Name() const { return _##Name; } \
public Q_SLOTS: \
void set##Name(Type value) { if (_##Name != value) { _##Name = value; Q_EMIT Name##Changed(value); } } \
Q_SIGNALS: \
void Name##Changed(Type)
// end macro
Due to macro expansion combined with `moc` I'm using `Q_SIGNALS`, `Q_SLOTS`
and `Q_EMIT`. The regular `signals`, `slots` and `emit` keywords do not work
in this construction. These macro's can also be used [if you want to use a
third-party signals and slots system]
(https://doc.qt.io/qt-6/signalsandslots.html#using-qt-with-3rd-party-signals-and-slots).
You can use it like this:
QP_V(property Type, property Name);
Example:
QP_V(bool, myBool);
The only thing I haven't got working is capitalization of function names.
Convention is to use `setMyThingChanged`. With the macro, that becomes `setmyThingChanged`.
You can capitalize you variable to fix that.
The macro is simple enough that you can easily update it for for example
`CONSTANT` properties or read-only properties (without a `WRITE` method).
### Usage example:
In [my monitoring app](https://leafnode.nl) there is an update check, which
uses a `Q_PROPERTY`. That is now just one line:
```
QP_V(bool, newVersionAvailable);
```
Instead of all of these lines in the header file:
private:
Q_PROPERTY(bool newVersionAvailable READ newVersionAvailable WRITE setNewVersionAvailable NOTIFY newVersionAvailableChanged FINAL)```
public:
bool newVersionAvailable() const;
signals:
void newVersionAvailableChanged(bool newVersionAvailable);
public slots:
setNewVersionAvailable(bool newNewVersionAvailable);
private:
bool _newVersionAvailable = false;
And in the implementation (`.cpp`) file:
bool MyClass::newVersionAvailable() const
{
return _newVersionAvailable;
}
void MyClass::setNewVersionAvailable(bool newNewVersionAvailable)
{
if (_newVersionAvailable == newNewVersionAvailable)
return;
_newVersionAvailable = newNewVersionAvailable;
emit newVersionAvailableChanged(_newVersionAvailable);
}
Saving all that boilerplate code makes it easier to read the source and figure
out what actually happens and matters instead of hundreds and hundreds of
lines of boilerplate.
---
License:
All the text on this website is free as in freedom unless stated otherwise.
This means you can use it in any way you want, you can copy it, change it
the way you like and republish it, as long as you release the (modified)
content under the same license to give others the same freedoms you've got
and place my name and a link to this site with the article as source.
This site uses Google Analytics for statistics and Google Adwords for
advertisements. You are tracked and Google knows everything about you.
Use an adblocker like ublock-origin if you don't want it.
All the code on this website is licensed under the GNU GPL v3 license
unless already licensed under a license which does not allows this form
of licensing or if another license is stated on that page / in that software:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Just to be clear, the information on this website is for meant for educational
purposes and you use it at your own risk. I do not take responsibility if you
screw something up. Use common sense, do not 'rm -rf /' as root for example.
If you have any questions then do not hesitate to contact me.
See https://raymii.org/s/static/About.html for details.