Shared types
#[qenum]
- Support for Q_ENUM
and Q_ENUM_NS
Qt allows exposing enums to Qt's meta-object system, and thereby QML, with a set of macros:
Q_ENUM
is used to expose an enum that is a member of aQObject
Q_ENUM_NS
is used to expose an enum that is in a namespace.
CXX-Qt has support for both of these macros through the #[qenum]
attribute.
QObject
class enum (Q_ENUM
)
CXX-Qt relies on CXX to expose enums from Rust to C++ and vice-versa.
However, CXX only supports free enums that are not defined as part of a class.
CXX-Qt doesn't change this, it only additionally exposes the enum as part of a QObject
type to the meta-object system.
So any #[qenum]
in CXX-Qt is available as both a normal shared CXX enum and a Q_ENUM
inside the associated QObject
.
To expose a shared enum as a Q_ENUM
inside a QObject
class, add the #[qenum(...)]
attribute to the enum definition.
The argument to #[qenum(...)]
must be the name of a #[qobject]
that is defined in a extern "RustQt"
block.
It is currently not possible to add a #[qenum(...)]
to any extern "C++Qt"
QObject
s or a QObject
that is defined in another #[cxx_qt::bridge]
.
Example:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum(CustomBaseClass)]
/// State of the CustomBaseClass list model
enum State {
/// Another item is being added in the background
Running,
/// No items are being added in the background
Idle,
}
extern "RustQt" {
#[qobject]
#[base = QAbstractListModel]
#[qml_element]
#[qproperty(State, state)]
type CustomBaseClass = super::CustomBaseClassRust;
}
}
Registering the class enum with QML
Note that Qt provides access to enum variants through the name of the class it is registered with, not the enum name itself.
A side effect of this behavior is that the enum itself doesn't have to be registered with QML.
Only the QObject
class has to be registered.
In the previous example, the #[qml_element]
attribute on the #[qobject]
takes care of the registration.
Usage from QML:
BusyIndicator {
anchors {
right: content.right
bottom: content.bottom
margins: 15
}
running: root.activeModel.state === CustomBaseClass.Running
}
Namespaced enum (Q_ENUM_NS
)
If there is no class that the enum should be associated with, Qt still allows exposing the enum to the meta-object system, as long as it is inside a namespace.
If there is a namespace associated with a shared enum simply add the #[qenum]
attribute and CXX-Qt will expose it using Q_ENUM_NS
.
Note that the namespace doesn't have to be specified on the enum directly, the enum can inherit the namespace from the surrounding bridge. This follows normal CXX namespacing rules.
Example:
#[cxx_qt::bridge]
pub mod qobject {
#[qenum]
#[namespace = "Colors"]
/// An enum of colors
enum Color {
/// Red
Red,
/// Green
Green,
/// Blue
Blue,
}
}
📝 Note: Unfortunately, an important Qt limitation also applies to CXX-Qt. Namely, for any given namespace, there must be at most one bridge that exposes
#[qenum]
enums through that namespace. One bridge may expose enums through multiple namespaces, however.
Registering the namespaced enum with QML
Whilst Q_ENUM_NS
creates the appropriate meta-objects, it doesn't add them to QML automatically.
Like with Q_ENUM
, access to the enum variants also doesn't happen through the enum directly, but rather the surrounding namespace.
Therefore, the namespace must be registered with the meta-object system and then exposed to QML.
CXX-Qt automatically registers the namespace of a namespaced #[qenum]
with the meta-object system.
Registration with QML can then be done by placing a qnamespace!("...")
macro inside the bridge that defines the namespaced #[qenum]
and adding a #[qml_element]
attribute.
#[cxx_qt::bridge]
pub mod qobject {
#[qml_element]
qnamespace!("Colors");
#[qenum]
#[namespace = "Colors"]
/// An enum of colors
enum Color {
/// Red
Red,
/// Green
Green,
/// Blue
Blue,
}
}
Usage from QML:
ToolButton {
text: qsTr("Red")
onClicked: rustInvokables.storeColorWithEnum(Colors.Red);
}