Skip to content

Instantly share code, notes, and snippets.

@Rolias
Last active September 27, 2023 21:58
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save Rolias/48d453a0490d36090193 to your computer and use it in GitHub Desktop.
Save Rolias/48d453a0490d36090193 to your computer and use it in GitHub Desktop.
Qt Auto Property Macros
#pragma once
#include <QObject>
//See Gist Comment for description, usage, warnings and license information
#define AUTO_PROPERTY(TYPE, NAME) \
Q_PROPERTY(TYPE NAME READ NAME WRITE NAME NOTIFY NAME ## Changed ) \
public: \
TYPE NAME() const { return a_ ## NAME ; } \
void NAME(TYPE value) { \
if (a_ ## NAME == value) return; \
a_ ## NAME = value; \
emit NAME ## Changed(value); \
} \
Q_SIGNAL void NAME ## Changed(TYPE value);\
private: \
TYPE a_ ## NAME;
#define READONLY_PROPERTY(TYPE, NAME) \
Q_PROPERTY(TYPE NAME READ NAME CONSTANT ) \
public: \
TYPE NAME() const { return a_ ## NAME ; } \
private: \
void NAME(TYPE value) {a_ ## NAME = value; } \
TYPE a_ ## NAME;
@Rolias
Copy link
Author

Rolias commented Nov 4, 2014

Overview

These macros are intended to reduce the amount of boilerplate code the user has to write when using the Qt Frameworks's Q_PROPERTY feature. The idea was to provide something similar to C#'s auto property feature.

public double myValue {get;set;}

I was after the lack of clutter not the syntax. This file contains two macros.

The First Macro

AUTO_PROPERTY(TYPE, NAME)

It will create a standard

Q_PROPERTY (TYPE, NAME READ NAME WRITE Name NOTIFY NAMEChanged) 

macro of the passed type and name. In addition, it will create a standard getter named NAME, setter named Name and signal named NAMEChanged(TYPE value) It will also create the member data variable. Note it does not use the more standard setName syntax, mostly because I didn't know how to do the capitalization trick. The member var is named with an a_ prefix because it is intended to remind the user to NOT use the member variable name directly. The user should use the property name instead. If you don't like the a_ prefix change the macro.

The Second Macro

READONLY_PROPERTY(TYPE, NAME)

will create a standard

Q_PROPERTY( TYPE NAME READ NAME CONST)

It will create the getter and the member variable name. It also creates a private setter function. The function is just named NAME, i.e. it doesn't use a set prefix. In this macro, the member variable again uses a_ but the user is expected to initialize this variable directly. All reads of the variable should be done through the property for consistency.

Example Usages

 AUTO_PROPERTY(QString, myProperty)
 READONLY_PROPERTY(double, myValueProp)

Usage Notes

Use these macros in the private: section of your header only. They use both public and private keywords and leave the header in the private section. Putting these macros directly under the Q_OBJECT macro at the top of the class is acceptable. If for some reason you have to use these macros in the public section it is your responsibility to add the public: keyword after the macro.

Warning!

Note that these macros are only intended to be used as shown. The parameters are NOT intended to be expressions but simply the type and name. The parameters aren't parenthesized in the body of the macro and the entire macro is not parenthesized. Enjoy responsibly.

Note on Initializers

If you uses these macros at the top of your class then the member variables they create will be the first ones in your class. Therefore, to make tools like lint happy, you should add these variables to your initializer list in the order they are declared; before any variables that come after these macros. If you want to fully initialize variables in the order they are declared then even AUTO_PROPERTY created variables will need to be accessed directly. There is no harm in doing this. In general I was trying to adhere to the philosophy of the member variables being hidden and only the property being used.

The MIT License (MIT)

Copyright (c) 2014 Syncor Systems, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@Rolias
Copy link
Author

Rolias commented Dec 4, 2014

12/4/2014 Fixed wayward pair of {} after private type declaration.

@hoensr
Copy link

hoensr commented May 11, 2016

This is a great idea, but unfortunately, setProperty does not work with this. The reason is that moc does not create the property because it doesn't understand the AUTO_PROPERTY macro. Do you know a solution for this?

Update: Aha! Moc does expand macros, since Qt5. I only have to take care that moc has the same include path as the C++ compiler, or otherwise make sure that moc actually finds PropertyHelper.h.

@tackelua
Copy link

tackelua commented Aug 16, 2019

Hi, thanks for your great working

I have some ideas for updating the file.

  • Use reference in function WRITE in AUTO_PROPERTY
    void NAME(const TYPE& value)

  • Remove function WRITE in READONLY_PROPERTY
    void NAME(TYPE value) {a_ ## NAME = value; }

  • Add define READ_PROPERTY with the Q_SIGNAL for qml can get the notify when property changed in C++.
    QML can not change the property.

You can see details in https://gist.github.com/tackelua/bcae0e346fc98184ba7a044315fd0a4c/revisions#diff-b6a69a742adff907546e80f3703e301a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment