Rust Qt 对象可以作为属性或参数相互嵌套。
嵌套对象通过指向其 QObject 表示的指针来引用。
首先,在桥接模块的 extern 块中正常定义一个类型。
rust
extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(i32, counter)]
type InnerObject = super::InnerObjectRust;
}
然后,可以通过使用 *mut T 将其作为属性、可调用方法的参数或信号参数使用。如下例所示,将 InnerObject 嵌套到 OuterObject 中。
需要使用 C++ CXX 类型作为 `T` 类型,而不是 Rust 结构体。
要访问嵌套对象的可变可调用方法和属性设置器,需要将 `*mut T` 转换为 `Pin<&mut T>`。
rust
#[cxx_qt::bridge]
pub mod qobject {
extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(i32, counter)]
type InnerObject = super::InnerObjectRust;
}
extern "RustQt" {
/// 一个信号,展示如何将另一个 QObject 作为参数引用
///
/// # 安全性
///
/// 由于使用了裸指针,这在 CXX 中被视为不安全
#[qsignal]
unsafe fn called(self: Pin<&mut InnerObject>, inner: *mut InnerObject);
}
extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(*mut InnerObject, inner)]
type OuterObject = super::OuterObjectRust;
/// 一个信号,展示如何将另一个 QObject 作为参数引用
///
/// # 安全性
///
/// 由于使用了裸指针,这在 CXX 中被视为不安全
#[qsignal]
unsafe fn called(self: Pin<&mut OuterObject>, inner: *mut InnerObject);
}
unsafe extern "RustQt" {
/// 打印给定内部 QObject 的计数
///
/// # 安全性
///
/// 由于在公共方法中解引用指针,这需要标记为不安全
#[qinvokable]
#[cxx_name = "printCount"]
unsafe fn print_count(self: Pin<&mut OuterObject>, inner: *mut InnerObject);
/// 重置存储在 Q_PROPERTY 中的内部 QObject 的计数器
#[qinvokable]
fn reset(self: Pin<&mut OuterObject>);
}
impl cxx_qt::Constructor<()> for OuterObject {}
}
use core::pin::Pin;
/// 内部 QObject
#[derive(Default)]
pub struct InnerObjectRust {
counter: i32,
}
/// 外部 QObject,具有指向内部 QObject 的 Q_PROPERTY
pub struct OuterObjectRust {
inner: *mut qobject::InnerObject,
}
impl Default for OuterObjectRust {
fn default() -> Self {
Self {
inner: std::ptr::null_mut(),
}
}
}
impl qobject::OuterObject {
/// 打印给定内部 QObject 的计数
///
/// # 安全性
///
/// 由于在公共方法中解引用指针,这需要标记为不安全
pub unsafe fn print_count(self: Pin<&mut Self>, inner: *mut qobject::InnerObject) {
if let Some(inner) = inner.as_ref() {
println!("内部对象的计数器属性: {}", inner.counter());
}
self.called(inner);
}
/// 重置存储在 Q_PROPERTY 中的内部 QObject 的计数器
pub fn reset(self: Pin<&mut Self>) {
// 需要将 *mut T 转换为 Pin<&mut T>,以便访问方法
if let Some(inner) = unsafe { self.inner().as_mut() } {
let pinned_inner = unsafe { Pin::new_unchecked(inner) };
// 现在可以像平常一样使用 pinned_inner
pinned_inner.set_counter(10);
}
// 获取 *mut T
let inner = *self.inner();
unsafe { self.called(inner) };
}
}
impl cxx_qt::Initialize for qobject::OuterObject {
/// 初始化 QObject,将一个信号连接到另一个信号
fn initialize(self: core::pin::Pin<&mut Self>) {
// 示例:将一个 QObject 的信号连接到另一个 QObject 的信号
// 这将触发 OuterObject::Called 以触发 InnerObject::Called
self.on_called(|qobject, obj| {
// 需要将 *mut T 转换为 Pin<&mut T>,以便访问方法
if let Some(inner) = unsafe { qobject.inner().as_mut() } {
let pinned_inner = unsafe { Pin::new_unchecked(inner) };
// 现在可以像平常一样使用 pinned_inner
unsafe {
pinned_inner.called(obj);
}
}
})
.release();
}
}