像Python枚举一样使用QEnum

xmjla07d  于 2023-02-06  发布在  Python
关注(0)|答案(2)|浏览(138)

假设我有一个python枚举:

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

我可以使用UserState.ONLINEUserState.OFFLINEUserState.BUSY访问不同的选项。如果我想把它变成QEnum以便在QML中使用它,我需要把它 Package 在QObject中,如下所示:

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

在QML中,我可以像在python中访问普通的python枚举一样访问这个枚举,但是如果我想从python访问这个枚举,我必须写UserState.Options.ONLINE
我怎样才能创建一个枚举,它可以使用相同的语法在python和QML中工作?

  • 我已经找到了一个解决方案,我将在答案部分发布。但是它涉及到嵌套的元类,这看起来不太对。我认为最佳的解决方案是一个从QObject和Enum派生的类,它具有每个上下文的所有功能。*
  • 如果有人能提供一个这样的版本,我会把它作为公认的答案。否则,你可以告诉我,为什么我的解决方案实际上是一个好的。*
2ul0zpep

2ul0zpep1#

下面是我写的一个类,它增加了我在这个问题中所要求的支持:

class CustomEnumMeta(type(Enum)):
    def __new__(cls, name, bases, attrs):
        # don't change type of base class
        if name == "CustomEnum":
            return super().__new__(cls, name, bases, attrs)

        original_attrs = attrs.copy()
        enum = super().__new__(cls, name, bases, attrs)

        class WrapperMeta(type(QObject)):
            def __new__(cls, wrapper_name, wrapper_bases, wrapper_attrs):
                return super().__new__(cls, wrapper_name, wrapper_bases, {**original_attrs, **wrapper_attrs})

        class Wrapper(QObject, metaclass=WrapperMeta):
            QEnum(enum)

        Wrapper.__name__ = name

        return Wrapper

class CustomEnum(Enum, metaclass=CustomEnumMeta):
    pass

CustomEnum类可以像普通的python枚举一样继承:

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

现在你可以像在QML中一样在python中使用UserState,这是一个对python和QML都有效的语句:UserState.ONLINE
我的实现工作原理是用一个QObject替换原来的类,嵌套原来的类,然后把嵌套类的所有属性复制到外部类,使它们可以从python访问。

hgc7kmma

hgc7kmma2#

您可以只在类内部调用QEnum并在类外部定义枚举。
示例(PySide6):

文件: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())

文件:主.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
    }
}

完整代码here

相关问题