What is the standard method for updating UI elements from a loop calling a web request in Rust using gtk-rs
? I am having trouble updating a label in a UI element to display some data from a web request.
Is there a standard way of doing this? The issues I have been having at the moment have all been related to passing data between threads and as such I am curious to know what is the common way of doing this?
I have a code example here where I get an error stating futures are not Send
. I am using fragile in order to pass a box into the thread.
At the moment I am trying to solve the issue of making my futures Send
however I am not sure that will solve the issue or just leave me with another similar problem.
use gtk::prelude::*;
use gtk::Orientation;
use adw::Application;
use std::thread;
use std::time::Duration;
use fragile;
const APP_ID: &str = "org.currency_trades";
fn main() {
let app = Application::builder().application_id(APP_ID).build();
app.connect_activate(build_ui);
app.run();
}
pub fn build_ui(app: &Application) -> gtk::Box {
let home_box = fragile::Fragile::new(gtk::Box::new(Orientation::Vertical, 15));
thread::spawn(move || {
let box_gbp = gtk::Box::new(Orientation::Horizontal, 250);
let gbp_label = gtk::Label::builder()
.label("GBP")
.margin_top(12)
.margin_start(50)
.build();
let gbp_price_label = gtk::Label::builder()
.label("Uninitialized")
.margin_top(12)
.margin_end(50)
.build();
box_gbp.append(&gbp_label);
box_gbp.append(&gbp_price_label);
home_box.get().append(&box_gbp);
loop {
let runtime = tokio::runtime::Runtime::new().unwrap();
std::thread::sleep(Duration::from_millis(1000));
let _ = runtime.block_on(runtime.spawn(async move {
let gbp_label_request = match reqwest::get("https://www.boredapi.com/api/activity").await {
Ok(label) => label,
Err(_) => panic!("Panic!")
};
let gbp_label = match gbp_label_request.text().await {
Ok(r) => r,
Err(_) => String::from("Unknown")
};
gbp_price_label.set_label(&gbp_label);
}));
}
});
return *home_box.get();
}
The associated error:
error: future cannot be sent between threads safely
--> src/main.rs:89:52
|
89 | let _ = runtime.block_on(runtime.spawn(async move {
| ____________________________________________________^
90 | | let gbp_label_request = match reqwest::get("https://www.boredapi.com/api/activity").await {
91 | | Ok(label) => label,
92 | | Err(_) => panic!("Panic!")
... |
100 | | gbp_price_label.set_label(&gbp_label);
101 | | }));
| |_____________^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `*mut c_void`
note: captured value is not `Send`
--> src/main.rs:100:17
|
100 | gbp_price_label.set_label(&gbp_label);
| ^^^^^^^^^^^^^^^ has type `gtk4::Label` which is not `Send`
note: required by a bound in `Runtime::spawn`
--> /Users/andy/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs:192:21
|
192 | F: Future + Send + 'static,
| ^^^^ required by this bound in `Runtime::spawn`
For more information about this error, try `rustc --explain E0271`.