#[qenum] - 支持 Q_ENUM 和 Q_ENUM_NS
Qt 允许通过一组宏将枚举暴露给 Qt 的元对象系统,从而暴露给 QML:
-
Q_ENUM 用于暴露作为 QObject 成员的枚举。
-
Q_ENUM_NS 用于暴露位于命名空间中的枚举。
CXX-Qt 通过 #[qenum] 属性支持这两种宏。
QObject 类枚举(Q_ENUM)
CXX-Qt 依赖 CXX 将枚举从 Rust 暴露给 C++,反之亦然。然而,CXX 仅支持不作为类一部分定义的自由枚举。CXX-Qt 并未改变这一点,它只是额外将枚举作为 QObject 类型的一部分暴露给元对象系统。因此,CXX-Qt 中的任何 #[qenum] 都可以作为普通的共享 CXX 枚举和关联 QObject 中的 Q_ENUM 使用。
要将共享枚举作为 Q_ENUM 暴露在 QObject 类中,请在枚举定义中添加 #[qenum(…)] 属性。#[qenum(…)] 的参数必须是在 extern “RustQt” 块中定义的 #[qobject] 的名称。
目前无法将 #[qenum(…)] 添加到任何 extern “C++Qt” QObject 或在另一个 #[cxx_qt::bridge] 中定义的 QObject。
示例:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum(CustomBaseClass)]
/// CustomBaseClass 列表模型的状态
enum State {
/// 后台正在添加另一个项目
Running,
/// 后台没有添加任何项目
Idle,
}
extern "RustQt" {
#[qobject]
#[base = "QAbstractListModel"]
#[qml_element]
#[qproperty(State, state)]
type CustomBaseClass = super::CustomBaseClassRust;
}
}
将类枚举注册到 QML
请注意,Qt 通过注册枚举的类名(而不是枚举名称本身)提供对枚举变体的访问。这种行为的一个副作用是,枚举本身不必注册到 QML,只有 QObject 类需要注册。
在前面的示例中,#[qml_element] 属性负责注册。
在 QML 中的使用:
BusyIndicator {
anchors {
right: content.right
bottom: content.bottom
margins: 15
}
running: root.activeModel.state === CustomBaseClass.Running
}
命名空间枚举(Q_ENUM_NS)
如果没有与枚举关联的类,Qt 仍然允许将枚举暴露给元对象系统,只要它位于命名空间中。
如果共享枚举关联了命名空间,只需添加 #[qenum] 属性,CXX-Qt 将使用 Q_ENUM_NS 暴露它。
请注意,命名空间不必直接在枚举上指定,枚举可以从周围的桥接模块继承命名空间。这遵循普通的 CXX 命名空间规则。
示例:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum]
#[namespace = "Colors"]
/// 颜色枚举
enum Color {
/// 红色
Red,
/// 绿色
Green,
/// 蓝色
Blue,
}
}
📝 注意:不幸的是,Qt 的一个重要限制也适用于 CXX-Qt。即,对于任何给定的命名空间,最多只能有一个桥接模块通过该命名空间暴露 `#[qenum]` 枚举。然而,一个桥接模块可以通过多个命名空间暴露枚举。
将命名空间枚举注册到 QML
虽然 Q_ENUM_NS 创建了适当的元对象,但它不会自动将它们添加到 QML。与 Q_ENUM 一样,对枚举变体的访问也不是通过枚举直接进行的,而是通过周围的命名空间进行的。
因此,必须将命名空间注册到元对象系统,然后暴露给 QML。CXX-Qt 会自动将命名空间 #[qenum] 的命名空间注册到元对象系统。
然后可以通过在定义命名空间 #[qenum] 的桥接模块中放置 qnamespace!(“…”) 宏并添加 #[qml_element] 属性来完成 QML 注册。
#[cxx_qt::bridge]
pub mod qobject {
#[qml_element]
qnamespace!("Colors");
#[qenum]
#[namespace = "Colors"]
/// 颜色枚举
enum Color {
/// 红色
Red,
/// 绿色
Green,
/// 蓝色
Blue,
}
}
在 QML 中的使用:
ToolButton {
text: qsTr("Red")
onClicked: rustInvokables.storeColorWithEnum(Colors.Red);
}