-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subclassing API #26
Comments
Could it possible use https://github.com/rust-lang-nursery/rust-bindgen way? |
Can you describe what is the way you mean? I found the doc page that says that they don't support cross language inheritance at all. |
They support inheritance (its the first stated) and even somehow work with vtable as I've seen in their code. |
Meanwhile I have created a QObject wrapper which holds the Rust closure for custom event filtering. Maybe it can be useful. https://github.com/snuk182/qt_core_custom_events |
That crate is exactly what I needed... but is outdated and broken. Is there any way to create event filter Update: I was using the crate wrong and the event filters do work. Still a bit of a hassle, but at least theres a solution. |
Hi Melvyn. Do you mind sharing a snippet of how you used it? Having a hard time making it work |
Sure, it's pretty messy (first attempts) but works: unsafe fn add_event_filters(self: &Rc<Self>) {
fn file_list_event_filter(obj: &mut QObject, event: &mut QEvent) -> bool {
// Function body has to be unsafe rather than function, because the filter requires an FnMut
// Which only safe function pointers are
unsafe {
if event.type_() == q_event::Type::DragEnter {
println!("Trace: received DragEnter event.");
// Transmute is safe because we check the event type
let devent: &mut QDragEnterEvent = transmute(event);
let mime_data = devent.mime_data().text().to_std_string();
// There is a method QMimeData.urls() but dealing with QLists is no fun
let urls: Vec<&str> = mime_data.lines().collect();
// Check if there are any files, excluding paths ending with / (dirs)
if devent.mime_data().has_urls()
&& urls
.iter()
.any(|url| !url.is_empty() && !url.ends_with('/'))
{
println!("Trace: event has valid data, accepting.");
devent.set_drop_action(DropAction::LinkAction);
// If we don't accept the DragEnter event, the DropEvent won't trigger
devent.accept();
return true;
}
} else if event.type_() == q_event::Type::Drop {
println!("Trace: received Drop event.");
// Transmute is safe because we check the event type
let devent: &mut QDropEvent = transmute(event);
let obj_type = CStr::from_ptr(obj.meta_object().class_name());
if obj_type.to_bytes() != b"QListWidget" {
println!(
"Error: received even on wrong QObject ({:?} instead of QWidget)",
obj_type
);
return false;
}
// Transmute is safe because we check the widget type
let list_widget: &mut QListWidget = transmute(obj);
let mime_data = devent.mime_data().text().to_std_string();
let urls: Vec<&str> = mime_data.lines().collect();
for file in urls.iter().filter(|f| !f.ends_with('/')) {
list_widget.add_item_q_string(qs(file.replacen("file://", "", 1)).as_ref());
}
devent.set_drop_action(DropAction::LinkAction);
devent.accept();
return true;
}
return false;
}
}
self.ui.lib_list.install_event_filter(
CustomEventFilter::new(file_list_event_filter).into_raw_ptr(),
);
} |
Thanks Melvyn. Had been experimenting with Paint events, still maneuvering around to make it work. 👨🏽💻 |
Let's have a C++ class that can be subclassed:
First, we create a C++ wrapper:
The wrapper exposes all protected functions of the base class and reimplements all its virtual functions. It allows to add callbacks for each virtual method. If a callback is not set, it calls base class implementation, as if the method was not reimplemented. It also allows to add a destructor callback for cleanup purposes.
Rust API changes the order of operations. First, the user needs to assign virtual functions. Then the object can be created:
If not all pure virtual functions were bound,
ExampleSubclassBuilder::new
function will panic.ExampleSubclassBuilder::new
creates a Rust struct that owns all lambdas and ensures that they are not deleted until the object itself is deleted. The struct is kept in memory by callingmem::forget
. The destructor callback is used to delete this struct when it's not needed anymore. If the base class's destructor is virtual, you can pass theExampleSubclass
object's ownership to the C++ library. When it delets the object, the Rust struct cleanup will still be done. If the base class's destructor is not virtual, the only correct way to release the resources is to letCppBox
delete the object.ExampleSubclass
Rust type is just a wrapper forExampleSubclass
C++ class, similar to other class wrappers. It exposes all its public methods, thus providing access to protected methods of the base class. Callback setters are not exposed.ExampleSubclass
will provide means to downcast it toExample
base type, just as any other derived class.Example of initialization of a Rust struct with a subclass field:
The text was updated successfully, but these errors were encountered: