Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use QEnum like a Python Enum

Let's say I have a python enum:

class UserState(Enum):
    OFFLINE = auto()
    ONLINE = auto()
    BUSY = auto()

I can access the different options with UserState.ONLINE, UserState.OFFLINE or UserState.BUSY. If I wanted to make this a QEnum so I can use it in QML, I'd need to wrap it inside a QObject like this:

class UserState(QObject):
    @QEnum
    class Options(Enum):
        OFFLINE = auto()
        ONLINE = auto()
        BUSY = auto()

In QML I can access this enum now the same way I'd access a normal python enum in python. However if I wanted to access this enum from python, I'd have to write UserState.Options.ONLINE.

How can I create an enum that will work in python as well as QML using the same syntax?

I have found a solution for this which I will post in the answers section. However it involves nested metaclasses which just doesn't look right. I think the optimal solution would be a class that derives from QObject as well as Enum to have all the functionality for every context.

If anyone can provide a version which works like that, I will make that the accepted answer. Otherwise you can tell me, why my solution actually is a good one.

like image 384
Tim Woocker Avatar asked May 24 '26 06:05

Tim Woocker


1 Answers

You can just call QEnum inside the class and define the enum outside.

Example (PySide6):

file: main.py

import sys
from enum import Enum
from pathlib import Path

from PySide6.QtCore import Property, QEnum, QObject
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import (
    QmlElement,
    QQmlApplicationEngine,
    qmlRegisterSingletonInstance,
)

QML_IMPORT_NAME = "com.example.app"
QML_IMPORT_MAJOR_VERSION = 1


class Status(Enum):
    Connected, Disconnected, Stale = range(3)


@QmlElement
class Enums(QObject):
    QEnum(Status)


class App(QObject):
    def __init__(self):
        super().__init__(None)

    @Property(int, constant=True)
    def enumValue(self):
        return Status.Connected.value


if __name__ == "__main__":
    loop = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    app = App()
    qmlRegisterSingletonInstance(QObject, "com.example.app", 1, 0, "App", app)
    qml_file = Path(__file__).parent / "main.qml"
    engine.load(str(qml_file))

    sys.exit(loop.exec())

file: main.qml

import QtQuick
import com.example.app 1.0

Window {
    visible: true
    width: 1000
    height: 700
    title: "POC"

    Rectangle {
        color: App.enumValue == Enums.Status.Connected ? "green" : "red"
        anchors.fill: parent
    }
}

Full code here