slint
slint copied to clipboard
Document how to use models in multi-threaded environments
Hello,
I want to fill a combobox with all peripherals connected to my computer (windows), so I don't know the number of elements I have. I have tried different solutions, but I have the following problem :
NonNull<i_slint_core::sharedvector::SharedVectorInner<u8>> cannot be shared between threads safely
within [slint::SharedString], the trait Sync is not implemented for NonNull<i_slint_core::sharedvector::SharedVectorInner<u8>>
required because it appears within the type [SharedString]
required for &[slint::SharedString] to implement std::marker::Send
how can I safely change my combobox depending on the USB peripherals I am connecting to my computer ?
Thanks for opening an issue.
Please paste more code of what you're trying to do.
SharedVector and SharedString should be Send, but are not Sync.
Maybe you need to use a Mutex.
Or maybe you need to use slint::invoke_from_event_loop to pass the data back to the UI thread.
hello,
I've tried to send a sharedVector or sharedString but I have the previous error. I'am actually using the event_loop to update my combobox.
the code ( that is not the same anymore), is working, but as soon as I want to pass the vector, it doesn't not work:
println!("filling combo box");
let mut device_names_SS: Vec<SharedString> = Vec::new();
for i in 0.. device_names.len()
{
device_names_SS.push(device_names[i].clone().into());
}
println!("device_names__ss list {}", device_names_SS[0].clone());
window_weak.upgrade_in_event_loop(move |window|
{
window.set_usbList([device_names_SS[0].clone()].into());
}).unwrap();
The types are a bit confusing, but this is possible. Here's a snippet that will convert any iterable container into a Slint model:
fn slint_string_arr<I>(a: I) -> slint::ModelRc<SharedString>
where
I: IntoIterator,
I::Item: Into<SharedString>
{
let shared_string_vec: Vec<SharedString> = a
.into_iter()
.map(|s| s.into())
.collect();
ModelRc::new(VecModel::from(shared_string_vec))
}
// then...
window_weak.upgrade_in_event_loop(move |window| {
window.set_usbList(slint_string_arr(device_names.clone()))
}).unwrap();
Perhaps this conversion could be provided by Slint itself to simplify usecases like these.
Perhaps this conversion could be provided by Slint itself to simplify usecases like these.
In this case, it should be as simple as:
window_weak.upgrade_in_event_loop(move |window| {
window.set_usbList(ModelRc::new(VecModel::from(device_names_SS)));
}).unwrap();
Maybe there could be some simplification for this parent to convert a Vec to a ModelRc directly, or maybe we need better documentation somehow?
It is nowadays a rather common use-case to collect data in separate threads, with the objective of feeding the final data into models. Our documentation for Models - for example at https://slint.dev/releases/1.3.2/docs/rust/slint/struct.ModelRc#example - could include instructions how this is best done, i.e. how to deal with !send errors and the like.
The types are a bit confusing, but this is possible. Here's a snippet that will convert any iterable container into a Slint model:
fn slint_string_arr<I>(a: I) -> slint::ModelRc<SharedString> where I: IntoIterator, I::Item: Into<SharedString> { let shared_string_vec: Vec<SharedString> = a .into_iter() .map(|s| s.into()) .collect(); ModelRc::new(VecModel::from(shared_string_vec)) } // then... window_weak.upgrade_in_event_loop(move |window| { window.set_usbList(slint_string_arr(device_names.clone())) }).unwrap();Perhaps this conversion could be provided by Slint itself to simplify usecases like these. I am back on that project, and perfect this work well. Thanks a lot. I was doing it another way around, but this is better.
However this following solution doesn't work : window.set_usbList(ModelRc::new(VecModel::from(device_names_SS)));
I think it could be very usefull to have an easy way .