Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How can I interact with the target widget from a drop event
I'm trying to update a ListBox widget after dropping some files on it.
This is the relevant part of my current code:
fn on_file_drop(target: &DropTarget,
value: &Value,
_x: f64,
_y: f64) -> bool {
if let Ok(file_list) = value.get::<FileList>() {
let list_box = target.widget().unwrap();
// ^^^^^^^^ this becomes a Gtk::Widget instead of Gtk::ListBox
for file in file_list.files() {
let basename = file.basename();
let path = file.path();
println!("{path:?} {basename:?}");
}
return true
}
false
}
fn build_ui(app: &Application) {
// more UI
let files_list = ListBox::builder()
.width_request(200)
.height_request(300)
.build();
let files_drop_target = DropTarget::builder()
.actions(DragAction::COPY)
.build();
files_drop_target.set_types(&[FileList::static_type()]);
files_drop_target.connect_drop(on_file_drop);
files_list.add_controller(files_drop_target);
// more UI
}
The problem is, that I don't understand (and can't find anything concrete in documentation or examples) on how to interact with the widget that is associated with the DropTarget.
When I try to explicitly convert the widget to a ListBox like this I get an error:
let list_box: ListBox = target.widget().unwrap().into();
the trait bound
gtk4::ListBox: From<gtk4::Widget>
is not satisfied required forgtk4::Widget
to implementInto<gtk4::ListBox>
I can't implement this example: https://github.com/gtk-rs/examples4/blob/master/src/bin/drag_and_drop.rs, the functions .drag_dest_set()
and .connect_drag_data_received()
don't even exist on my instanciated widgets.
How can I get a ListBox out of the target
argument, so I can interact with it? Or would I make my life much easier by implementing everything in a struct instead of just plain functions?
2 answers
You can get a &ListBox
from a &Widget
with downcast_ref
:
let list_box = target.widget().unwrap().downcast_ref::<ListBox>().unwrap();
0 comment threads
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
GeraldS | (no comment) | Aug 17, 2024 at 12:44 |
I managed to do this by changing my on_file_drop()
function into a closure and adding the glib::clone!
macro:
Macro
glib::clone
Macro for passing variables as strong or weak references into a closure.This macro can be useful in combination with closures, e.g. signal handlers, to reduce the boilerplate required for passing strong or weak references into the closure. It will automatically create the new reference and pass it with the same name into the closure.
My working code is:
files_drop_target.connect_drop(glib::clone!(
#[weak()]
files_list,
#[upgrade_or]
false,
move |_, data, _, _| {
if let Ok(file_list) = data.get::<FileList>() {
for file in file_list.files() {
let basename = file.basename().unwrap().display().to_string();
let path = file.path().unwrap().display().to_string();
let file_label = Label::builder()
.label(&basename)
.build();
files_list.append(&file_label);
}
return true
}
false
}));
I haven't managed yet to wrap my head around closures completely, but this is a large step forward.
0 comment threads