Is it possible to add a Q_PROPERTY which intakes a parameter?

383 Views Asked by At

I have a following Q_PROPERTYs declared and of course the respective glue code for it.

Q_PROPERTY(bool thisEnabled READ isThisEnabled NOTIFY thisEnabledChanged)
Q_PROPERTY(bool thatEnabled READ isThatEnabled NOTIFY thatEnabledChanged)
Q_PROPERTY(bool somethingEnabled READ isSomethingEnabled NOTIFY somethingEnabledChanged)
Q_PROPERTY(bool somethingElseEnabled READ isSomethingElseEnabled NOTIFY somethingElseEnabledChanged)

Above works great!

Question:
But, these Q_PROPERTYs are part of a class which will add more features in future and hence more Q_PROPERTYs. Please note that all would be of type bool.

Now my concern is that I don't want add 5 more Q_PROPERTYs to 5 more features added. Is there some way I can add a Q_PROPERTY which is checked in QML by passing a Q_ENUM? Something like below?

// QML code
Rectangle {
    id: some_rect
    visible: cppClass.isEnabled(some_qenum_value)
}

Issue with using a Q_INVOKABLE here:
I know that I could add a Q_INVOKABLE method but if I add a Q_INVOKABLE, I loose the dynamic binding feature of a Q_PROPERTY.

I am using Qt 5.15.9 commercial version.

1

There are 1 best solutions below

1
Stephen Quan On

Flags are the way to go. Since integers are 32-bit, technically, you can use this to store your 4 boolean values and you have the ability to scale up to 32 boolean values:

#ifndef MyClass_H
#define MyClass_H

#include <QObject>
#include <QtQml>
#include <QFlags>

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(MyFlags myFlags READ myFlags WRITE setMyFlags NOTIFY myFlagsChanged)
    QML_ELEMENT
public:
    MyClass(QObject*parent=nullptr) : QObject(parent) { }
    enum MyFlag
    {
        This = 1,
        That = 2,
        Something = 4,
        SomethingElse = 8
    };
    Q_FLAG(MyFlag)
    Q_FLAGS(MyFlags)
    Q_DECLARE_FLAGS(MyFlags, MyFlag)
signals:
    void myFlagsChanged();
protected:
    MyFlags m_myFlags;
    MyFlags myFlags() const { return m_myFlags; }
    void setMyFlags(MyFlags value)
    {
        if (value == m_myFlags)
        {
            return;
        }
        m_myFlags = value;
        emit myFlagsChanged();
    }
};

Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::MyFlags)

#endif

In QML, you can set the flags property by combining 0, 1 or more flags together with a bitwise | operator. e.g.

MyClass {
    id: myClass
    myFlags: MyClass.This
           | MyClass.That
           | MyClass.Something
           | MyClass.SomethingElse
}

Here is a QML for that demonstrates reading, setting, clearing each flag:

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import qt5enumapp 1.0
Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    Frame {
        ColumnLayout {
            Switch {
                text: qsTr("This")
                checked: (myClass.myFlags & MyClass.This) !== 0
                onToggled: myClass.myFlags = checked
                                      ? myClass.myFlags | MyClass.This
                                      : myClass.myFlags & ~MyClass.This
            }
            Switch {
                text: qsTr("That")
                checked: (myClass.myFlags & MyClass.That) !== 0
                onToggled: myClass.myFlags = checked
                                      ? myClass.myFlags | MyClass.That
                                      : myClass.myFlags & ~MyClass.That
            }
            Switch {
                text: qsTr("Something")
                checked: (myClass.myFlags & MyClass.Something) !== 0
                onToggled: myClass.myFlags = checked
                                      ? myClass.myFlags | MyClass.Something
                                      : myClass.myFlags & ~MyClass.Something
            }
            Switch {
                text: qsTr("Something Else")
                checked: (myClass.myFlags & MyClass.SomethingElse) !== 0
                onToggled: myClass.myFlags = checked
                                      ? myClass.myFlags | MyClass.SomethingElse
                                      : myClass.myFlags & ~MyClass.SomethingElse
            }
            Text {
                text: qsTr("myClass.myFlags=%1").arg(myClass.myFlags)
            }
        }
    }
    MyClass {
        id: myClass
    }
}

Below is another simplified version of the QML without the C++ class. It further illustrates how to read, set, and clear flags from your integer value:

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
    anchors.fill: parent
    readonly property int kThis: 1
    readonly property int kThat: 2
    readonly property int kSomething: 4
    readonly property int kSomethingElse: 8
    property int myFlags: 0
    Frame {
        ColumnLayout {
            Switch {
                text: qsTr("This")
                checked: (myFlags & kThis) !== 0
                onToggled: myFlags = checked
                                          ? myFlags | kThis
                                          : myFlags & ~kThis
            }
            Switch {
                text: qsTr("That")
                checked: (myFlags & kThat) !== 0
                onToggled: myFlags = checked
                                          ? myFlags | kThat
                                          : myFlags & ~kThat
            }
            Switch {
                text: qsTr("Something")
                checked: (myFlags & kSomething) !== 0
                onToggled: myFlags = checked
                                          ? myFlags | kSomething
                                          : myFlags & ~kSomething
            }
            Switch {
                text: qsTr("Something Else")
                checked: (myFlags & kSomethingElse) !== 0
                onToggled: myFlags = checked
                                          ? myFlags | kSomethingElse
                                          : myFlags & ~kSomethingElse
            }
            Text {
                text: qsTr("myFlags=%1").arg(myFlags)
            }
        }
    }
}

You can Try it Online!