某些 Qt API 要求你從抽象基類中重寫某些方法,例如 QAbstractItemModel。
為了支持直接從 Rust 中創建這樣的子類,CXX-Qt 提供了多種輔助工具。
某些基類可能需要特殊的構造參數。這可以通過使用自定義構造函數來實現。
訪問基類方法
要在 Rust 中訪問基類的方法,請使用 #[inherit] 宏。它可以放在 #[cxx_qt::bridge] 中的 extern “RustQt” 塊中的函數前面。
extern "RustQt" {#[qobject]#[base = "QAbstractListModel"]#[qml_element]#[qproperty(State, state)]type CustomBaseClass = super::CustomBaseClassRust;
}// 為基類(QAbstractItemModel)的 C++ 函數創建 Rust 綁定
extern "RustQt" {/// 從基類繼承的 beginInsertRows 方法#[inherit]#[cxx_name = "beginInsertRows"]unsafe fn begin_insert_rows(self: Pin<&mut CustomBaseClass>,parent: &QModelIndex,first: i32,last: i32,);/// 從基類繼承的 endInsertRows 方法#[inherit]#[cxx_name = "endInsertRows"]unsafe fn end_insert_rows(self: Pin<&mut CustomBaseClass>);/// 從基類繼承的 beginRemoveRows 方法#[inherit]#[cxx_name = "beginRemoveRows"]unsafe fn begin_remove_rows(self: Pin<&mut CustomBaseClass>,parent: &QModelIndex,first: i32,last: i32,);/// 從基類繼承的 endRemoveRows 方法#[inherit]#[cxx_name = "endRemoveRows"]unsafe fn end_remove_rows(self: Pin<&mut CustomBaseClass>);/// 從基類繼承的 beginResetModel 方法#[inherit]#[cxx_name = "beginResetModel"]unsafe fn begin_reset_model(self: Pin<&mut CustomBaseClass>);/// 從基類繼承的 endResetModel 方法#[inherit]#[cxx_name = "endResetModel"]unsafe fn end_reset_model(self: Pin<&mut CustomBaseClass>);
}unsafe extern "RustQt" {/// 清除 QAbstractListModel 中的行#[qinvokable]pub fn clear(self: Pin<&mut CustomBaseClass>);
}impl qobject::CustomBaseClass {/// 清除 QAbstractListModel 中的行pub fn clear(mut self: Pin<&mut Self>) {unsafe {self.as_mut().begin_reset_model();self.as_mut().rust_mut().id = 0;self.as_mut().rust_mut().vector.clear();self.as_mut().end_reset_model();}}
}
完整示例
這段代碼實現了一個 QAbstractListModel 子類。為此,Rust 中實現的 clear 方法需要調用基類中的 beginResetModel 及相關方法,這些方法通過使用 #[inherit] 來訪問。有關特定子類化要求的更多詳細信息,請參閱 Qt 文檔。
類似于 CXX,extern “RustQt” 塊中的方法可以使用 #[inherit] 屬性標記,并且對可使用的類型有相同的限制。此外,self 類型必須是 self: Pin<&mut qobject::T> 或 self: &qobject::T,其中 qobject::T 必須引用在 #[cxx_qt::bridge] 中用 #[qobject] 標記的 QObject。
如果 Rust 名稱應與 C++ 方法名稱不同(例如,由于 snake_case 與 camelCase 的差異),請使用 #[cxx_name = “myFunctionName”] 或 #[rust_name = “my_function_name”] 屬性。
#[inherit]` 也可以用于 `extern RustQt` 塊中存在于基類上的信號。
重寫基類方法
CXX-Qt 允許生成具有實現繼承所需的 C++ 修飾符的可調用方法。這樣,方法可以被重寫、聲明為 virtual 或 final。
C++ 關鍵字 CXX-Qt 屬性
override #[cxx_override]
virtual #[cxx_virtual]
final #[cxx_final]
以下示例重寫了從 QAbstractListModel 繼承的 data 方法。
extern "RustQt" {#[qobject]#[base = "QAbstractListModel"]#[qml_element]#[qproperty(State, state)]type CustomBaseClass = super::CustomBaseClassRust;
}unsafe extern "RustQt" {#[qinvokable]#[cxx_override]fn data(self: &CustomBaseClass, index: &QModelIndex, role: i32) -> QVariant;
}impl qobject::CustomBaseClass {/// 檢索給定索引和角色的數據pub fn data(&self, index: &QModelIndex, role: i32) -> QVariant {let role = qobject::Roles { repr: role };if let Some((id, value)) = self.vector.get(index.row() as usize) {return match role {qobject::Roles::Id => QVariant::from(id),qobject::Roles::Value => QVariant::from(value),_ => QVariant::default(),};}QVariant::default()}
}
完整示例
當使用 cxx_override 重寫方法時,可以通過結合使用 #[inherit] 和 #[cxx_name] 屬性來訪問基類版本的方法。在這種情況下,基類版本的函數必須使用不同的名稱,因為 Rust 不能在一個類型上擁有兩個同名函數。
示例:
extern "RustQt" {#[qobject]#[base = "QAbstractListModel"]#[qml_element]#[qproperty(State, state)]type CustomBaseClass = super::CustomBaseClassRust;
}unsafe extern "RustQt" {/// 從基類繼承的 canFetchMore 方法#[cxx_name = "canFetchMore"]#[inherit]fn base_can_fetch_more(self: &CustomBaseClass, parent: &QModelIndex) -> bool;/// 從基類繼承的 index 方法#[inherit]fn index(self: &CustomBaseClass,row: i32,column: i32,parent: &QModelIndex,) -> QModelIndex;
}unsafe extern "RustQt" {/// 返回基類是否可以獲取更多數據// 示例:重寫 C++ 虛方法并調用基類實現。#[qinvokable]#[cxx_override]#[cxx_name = "canFetchMore"]fn can_fetch_more(self: &CustomBaseClass, parent: &QModelIndex) -> bool;
}impl qobject::CustomBaseClass {/// 返回基類是否可以獲取更多數據// 示例:重寫 C++ 虛方法并調用基類實現。pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool {self.base_can_fetch_more(parent)}
}