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.