non_blocking_sync/
non_blocking_sync.rs

1use std::time::Duration;
2
3use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
4use relm4::{Component, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt};
5
6struct App {
7    counter: u8,
8}
9
10#[derive(Debug)]
11enum Msg {
12    Increment,
13    Decrement,
14}
15
16#[relm4::component]
17impl Component for App {
18    type Init = ();
19    type Input = ();
20    type Output = ();
21    type CommandOutput = Msg;
22    type Widgets = AppWidgets;
23
24    view! {
25        gtk::Window {
26            set_title: Some("Async Counter"),
27            set_default_size: (300, 100),
28
29            gtk::Box {
30                set_orientation: gtk::Orientation::Vertical,
31                set_margin_all: 5,
32                set_spacing: 5,
33
34                gtk::Button {
35                    set_label: "Increment",
36                    // Messages are fully async, no blocking!
37                    connect_clicked[sender] => move |_| {
38                        sender.spawn_oneshot_command(|| {
39                            std::thread::sleep(Duration::from_secs(1));
40                            Msg::Increment
41                        })
42                    },
43                },
44
45                gtk::Button::with_label("Decrement") {
46                    connect_clicked[sender] => move |_| {
47                        sender.spawn_oneshot_command(|| {
48                            std::thread::sleep(Duration::from_secs(1));
49                            Msg::Decrement
50                        })
51                    },
52                },
53
54                gtk::Label {
55                    set_margin_all: 5,
56                    #[watch]
57                    set_label: &format!("Counter: {}", model.counter),
58                },
59            },
60        }
61    }
62
63    fn init(
64        _: Self::Init,
65        root: Self::Root,
66        sender: ComponentSender<Self>,
67    ) -> ComponentParts<Self> {
68        let model = App { counter: 0 };
69
70        let widgets = view_output!();
71
72        ComponentParts { model, widgets }
73    }
74
75    fn update_cmd(
76        &mut self,
77        msg: Self::CommandOutput,
78        _sender: ComponentSender<Self>,
79        _root: &Self::Root,
80    ) {
81        match msg {
82            Msg::Increment => {
83                self.counter = self.counter.wrapping_add(1);
84            }
85            Msg::Decrement => {
86                self.counter = self.counter.wrapping_sub(1);
87            }
88        }
89    }
90}
91
92fn main() {
93    let app = RelmApp::new("relm4.example.non_blocking_async");
94    app.run::<App>(());
95}