Deriving from a cxx-qt QObject child #1031
-
Hi there, Another day, another question from my side. I am trying to have inheritance between my cxx-qt objects. In my particular case, I derive a class from QQuickItem, then I want another class to derive from this class. The code is at the bottom of my message. The problem I am running into is that it seems all cxx-qt generated items derive from
I don't know if there is a way around this, and don't see any similar cases in the examples. I think not being able to do inheritance like this will put some serious constraints on code reusability. I guess one way could be to make the base class not be a Qt-derived object at all, but implement the common functionality via traits or the like. But that would not allow for e.g. inheriting properties and invokeables. Thanks in any case! The relevant code: Base class: use crate::logging::macros::*;
shoop_log_unit!("Frontend.FindParentBackendWrapper");
use std::pin::Pin;
#[cxx_qt::bridge]
pub mod qobj_find_parent_backend_wrapper {
unsafe extern "C++" {
include!(<QtQuick/QQuickItem>);
type QQuickItem;
}
unsafe extern "RustQt" {
#[qobject]
#[base = "QQuickItem"]
#[qproperty(*mut QQuickItem, backend_wrapper)]
#[qproperty(bool, backend_wrapper_initialized)]
type FindParentBackendWrapper = super::FindParentBackendWrapperRust;
}
unsafe extern "C++" {
include!("cxx-qt-shoop/qquickitem_parent.h");
#[rust_name = "maybe_parent_qquickitem_qquickitem_findparentbackendwrapper"]
fn maybe_parent_qquickitem(item : &QQuickItem) -> *mut QQuickItem;
#[rust_name = "maybe_parent_qquickitem_findparentbackendwrapper"]
fn maybe_parent_qquickitem(item : &FindParentBackendWrapper) -> *mut QQuickItem;
include!("cxx-qt-shoop/qobject_classname.h");
#[rust_name = "qobject_class_name_qquickitem_findparentbackendwrapper"]
fn qobject_class_name(obj : &QQuickItem) -> &str;
include!("cxx-qt-shoop/cast_ptr.h");
#[rust_name = "cast_ptr_findparentbackendwrapper_qquickitem"]
unsafe fn cast_ptr(item : *mut FindParentBackendWrapper) -> *mut QQuickItem;
}
unsafe extern "RustQt" {
#[qinvokable]
unsafe fn rescan_parents(self: Pin<&mut FindParentBackendWrapper>);
}
unsafe extern "C++" {
include!("cxx-qt-shoop/make_unique.h");
#[rust_name = "make_unique_findparentbackendwrapper"]
fn make_unique() -> UniquePtr<FindParentBackendWrapper>;
}
impl cxx_qt::Constructor<(*mut QQuickItem,), NewArguments=(*mut QQuickItem,)> for FindParentBackendWrapper {}
impl cxx_qt::Constructor<(), NewArguments=()> for FindParentBackendWrapper {}
}
use qobj_find_parent_backend_wrapper::*;
unsafe fn find_parent_backend(item : *mut QQuickItem) -> Result<*mut QQuickItem, String> {
if item.is_null() {
return Err(String::from("Could not find back-end item."));
}
let is_backend = qobject_class_name_qquickitem_findparentbackendwrapper(item.as_ref().unwrap()) == "Backend";
if is_backend {
return Ok(item);
}
let parent = maybe_parent_qquickitem_qquickitem_findparentbackendwrapper(item.as_ref().unwrap());
return find_parent_backend (parent);
}
pub struct FindParentBackendWrapperRust {
backend_wrapper : *mut QQuickItem,
backend_wrapper_initialized : bool,
}
impl Default for FindParentBackendWrapperRust {
fn default() -> FindParentBackendWrapperRust {
FindParentBackendWrapperRust {
backend_wrapper : std::ptr::null_mut(),
backend_wrapper_initialized : false,
}
}
}
impl FindParentBackendWrapper {
pub unsafe fn rescan_parents(mut self: Pin<&mut FindParentBackendWrapper>) {
let self_ptr = self.as_mut().get_unchecked_mut() as *mut FindParentBackendWrapper;
let self_qquick_ptr = cast_ptr_findparentbackendwrapper_qquickitem(self_ptr);
let backend = find_parent_backend(self_qquick_ptr).unwrap();
self.set_backend_wrapper(backend);
}
}
impl cxx_qt::Constructor<(*mut QQuickItem,)> for FindParentBackendWrapper {
type BaseArguments = (*mut QQuickItem,); // Will be passed to the base class constructor
type InitializeArguments = (); // Will be passed to the "initialize" function
type NewArguments = (*mut QQuickItem,); // Will be passed to the "new" function
fn route_arguments(args: (*mut QQuickItem,)) -> (
Self::NewArguments,
Self::BaseArguments,
Self::InitializeArguments
) {
(args, args, ())
}
fn new(_parent : (*mut QQuickItem,)) -> FindParentBackendWrapperRust {
FindParentBackendWrapperRust::default()
}
}
impl cxx_qt::Constructor<()> for FindParentBackendWrapper {
type BaseArguments = (); // Will be passed to the base class constructor
type InitializeArguments = (); // Will be passed to the "initialize" function
type NewArguments = (); // Will be passed to the "new" function
fn route_arguments(_args: ()) -> (
Self::NewArguments,
Self::BaseArguments,
Self::InitializeArguments
) {
((), (), ())
}
fn new(_args: ()) -> FindParentBackendWrapperRust {
FindParentBackendWrapperRust::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_class_name() {
let obj = make_unique_findparentbackendwrapper();
unsafe {
let ptr = obj.into_raw();
let quick = cast_ptr_findparentbackendwrapper_qquickitem(ptr);
let classname = qobject_class_name_qquickitem_findparentbackendwrapper(quick.as_ref().unwrap());
assert_eq!(classname, "FindParentBackendWrapper");
}
}
} Child class: use crate::logging::macros::*;
shoop_log_unit!("Frontend.AutoConnect");
// use crate::cxx_qt_shoop::qobj_find_parent_backend_wrapper;
#[cxx_qt::bridge]
pub mod qobj_autoconnect {
unsafe extern "C++" {
include!(<QtQuick/QQuickItem>);
type QQuickItem;
}
unsafe extern "C++" {
include!("cxx-qt-gen/qobj_find_parent_backend_wrapper.cxxqt.h");
}
unsafe extern "RustQt" {
#[qobject]
#[base = "FindParentBackendWrapper"]
type AutoConnect = super::AutoConnectRust;
}
unsafe extern "C++" {
include!("cxx-qt-shoop/make_unique.h");
#[rust_name = "make_unique_autoconnect"]
fn make_unique() -> UniquePtr<AutoConnect>;
}
unsafe extern "C++" {
include!("cxx-qt-shoop/qobject_classname.h");
#[rust_name = "qobject_class_name_autoconnect"]
fn qobject_class_name(obj : &AutoConnect) -> &str;
}
impl cxx_qt::Constructor<(*mut QQuickItem,), NewArguments=(*mut QQuickItem,)> for AutoConnect {}
impl cxx_qt::Constructor<(), NewArguments=()> for AutoConnect {}
}
pub struct AutoConnectRust {
}
impl Default for AutoConnectRust {
fn default() -> AutoConnectRust {
AutoConnectRust {}
}
}
impl cxx_qt::Constructor<(*mut QQuickItem,)> for AutoConnect {
type BaseArguments = (*mut QQuickItem,); // Will be passed to the base class constructor
type InitializeArguments = (); // Will be passed to the "initialize" function
type NewArguments = (*mut QQuickItem,); // Will be passed to the "new" function
fn route_arguments(args: (*mut QQuickItem,)) -> (
Self::NewArguments,
Self::BaseArguments,
Self::InitializeArguments
) {
(args, args, ())
}
fn new(_parent : (*mut QQuickItem,)) -> AutoConnectRust {
AutoConnectRust::default()
}
}
impl cxx_qt::Constructor<()> for AutoConnect {
type BaseArguments = (); // Will be passed to the base class constructor
type InitializeArguments = (); // Will be passed to the "initialize" function
type NewArguments = (); // Will be passed to the "new" function
fn route_arguments(_args: ()) -> (
Self::NewArguments,
Self::BaseArguments,
Self::InitializeArguments
) {
((), (), ())
}
fn new(_args: ()) -> AutoConnectRust {
AutoConnectRust::default()
}
}
#[cfg(test)]
mod tests {
use super::qobj_autoconnect::*;
#[test]
fn test_class_name() {
let obj = make_unique_autoconnect();
let classname = qobject_class_name_autoconnect (obj.as_ref().unwrap());
assert_eq!(classname, "AutoConnect");
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Really interesting, i don't think any of us have tried / thought of multiple inheritance on the Rust side. I was only thinking that C++ could inherit from Rust or Rust could inherit from C++. But here we have Rust inheriting from Rust which inherits from C++. Now for the problem itself, we automatically implement locking on any methods that are exposed to C++ via the RustQt block so that multi-threading can be safe. Any Rust QObject that has threading/locking enabled inherits from So I wonder if we also pass the template onto the Meanwhile a workaround with the current could be to try disabling the locking on the base class. This would mean that your base class methods would be unsafe if called from multiple threads and you cannot access the threading helper on that class but would be interesting if that compiles (as that would hint that having multiple templated inheritances is OK (eg the CxxQtType). You can try this out by adding |
Beta Was this translation helpful? Give feedback.
Opened an issue here #1034