像 Python 枚举一样使用 QEnum

Use QEnum like a Python Enum

假设我有一个 python 枚举:

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

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

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

在 QML 中,我现在可以像访问 python 中的普通 python 枚举一样访问此枚举。但是,如果我想从 python 访问此枚举,我必须编写 UserState.Options.ONLINE.

如何使用相同的语法创建可在 python 和 QML 中使用的枚举?

我找到了一个解决方案,我将在答案部分 post。然而,它涉及嵌套的 metaclasses,这看起来并不正确。我认为最佳解决方案是 class 派生自 QObject 以及 Enum 以具有每个上下文的所有功能。

如果有人可以提供类似的版本,我会将其作为可接受的答案。 否则你可以告诉我,为什么我的解决方案实际上是一个好方案。

这是我写的class,它增加了我在问题中要求的支持:

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 class 可以像普通 python 枚举一样被继承:

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

现在您可以像在 QML 中一样在 python 中使用 UserState。这对 python 和 QML 都是有效的声明:UserState.ONLINE

我的实现工作是用 QObject 替换原来的 class,嵌套原来的 class。然后将嵌套 class 的所有属性复制到外部 class 以使它们可从 python.

访问