Sunday, June 14, 2020

Synthesize Qt Settings

I frequently create classes that I use as an interface to settings in my apps. Using a single class with accessors makes the code readable, safer and simple to maintain. Unfortunately, doing this requires to create getters and setters for every entry in the settings file, which is a bit bothering. Also, QSettings is not a QObject and cannot provide signals to notify changes.

My use cases are typically very simple, so I created a couple of macros that synthesise classes for me. Macros synthesise a reentrant class that can be used to access settings and a notifier, that can be used to get notifications of the changes. An example of definition of the class is:

L_DECLARE_SETTINGS(LSettingsTest, new QSettings("settings.ini", QSettings::IniFormat))
L_DEFINE_VALUE(QString, string1, QString("string1"), toString)
L_DEFINE_VALUE(QSize, size, QSize(100, 100), toSize)
L_DEFINE_VALUE(double, temperature, -1, toDouble)
L_DEFINE_VALUE(QByteArray, image, QByteArray(), toByteArray)
L_END_CLASS

L_DECLARE_SETTINGS(LSettingsTestSec1, new QSettings("settings.ini", QSettings::IniFormat), "SECTION_1")
L_DEFINE_VALUE(QString, string2, QString("string2"), toString)
L_END_CLASS

this will let you instantiate objects of class LSettingsTest and LSettingsTestSec1, and access entries with strong typed methods. Also, by calling LSettingsTest::notifier(), you can get a reference to the unique notifier. By setting an instance as a context property, you can get notifications and you can update settings from QML. You can find some more info in the repo https://github.com/carlonluca/lqtutils and an example using Qt Quick here: https://github.com/carlonluca/lqtutils/tree/master/LQtUtilsQuick.
Bye! ;-)

Thursday, May 28, 2020

Synthesize Qt properties

The are some utils that I use in most of my Qt projects. I'm a bit fed up of copy-pasting those every time I need something, so I created a project containing tools that are of frequent use when I write Qt apps, regardless of the type of app.

The only interesting tool I added yet is the synthesizer of Q_PROPERTY's. You can use the macros:
L_RW_PROP
L_RO_PROP
to synth├ętise props, with getter, setter and notifications. Each macro is overloaded: with 3 params, you do not have initialisation, adding a 4th param, also initialises the variable to the provided value. Also, I frequently need QObject that are just containers of properties, to be used in QML. I added these two macros to spare some lines:
L_BEGIN_CLASS(<class_name>)
L_END_CLASS
A class like:
class Fraction : public QObject
{
    Q_OBJECT
    Q_PROPERTY(double numerator READ numerator WRITE setNumerator NOTIFY numeratorChanged)
    Q_PROPERTY(double denominator READ denominator WRITE setDenominator NOTIFY denominatorChanged)
public:
    Fraction(QObject* parent = nullptr) : QObject(parent) {}
    double numerator() const {
        return m_numerator;
    }
    double denominator() const {
        return m_denominator;
    }
public slots:
    void setNumerator(double numerator) {
        if (m_numerator == numerator)
            return;
        m_numerator = numerator;
        emit numeratorChanged(numerator);
    }
    void setDenominator(double denominator) {
        if (m_denominator == denominator)
            return;
        m_denominator = denominator;
        emit denominatorChanged(denominator);
    }
signals:
    void numeratorChanged(double numerator);
    void denominatorChanged(double denominator);
private:
    double m_numerator;
    double m_denominator;
};
can be simplified to:
L_BEGIN_CLASS(Fraction)
L_RW_PROP(double, numerator, setNumerator)
L_RW_PROP(double, denominator, setDenominator)
L_END_CLASS
I'm sure there are other similar approaches out there, but if you need it, you can simply add this repo as a submodule like I do: https://github.com/carlonluca/lqtutils.
Bye! ;-)