programmazione:rust:gtkrs:gestione_memoria
Indice
Appunti sulla gestione della memoria in Gtkrs e Rust
Autore: Fabio Di Matteo
Ultima revisione: 30/04/2026 14:08
Alcuni esempi che mostrano alcuni casi tipici di gestione della memoria.
Miei progetti che implementano le conoscenze affrontate in questo articolo:
Due button che incrementano una stessa variabile intera
use gtk4::prelude::*; use gtk4::{Application, ApplicationWindow, glib, Button,Box,Orientation}; use std::rc::Rc; use std::cell::Cell; const APP_ID: &str = "org.gtk_rs.test_vari"; fn main() -> glib::ExitCode { // Create a new application let app = Application::builder().application_id(APP_ID).build(); // Connect to "activate" signal of `app` app.connect_activate(build_ui); // Run the application app.run() } fn build_ui(app: &Application) { let button0 = Button::builder() .label("Press me!") .margin_top(12) .margin_bottom(12) .margin_start(12) .margin_end(12) .build(); let button1 = Button::builder() .label("Press me, I'm the button two!'") .margin_top(12) .margin_bottom(12) .margin_start(12) .margin_end(12) .build(); let gtk_box = Box::builder() .orientation(Orientation::Vertical) .build(); gtk_box.append(&button0); gtk_box.append(&button1); let counter = Rc::new(Cell::new(0)); let count = counter.clone(); button0.connect_clicked(move |button0| { count.set(count.get()+1); button0.set_label(&count.get().to_string()); }); let count = counter.clone(); button1.connect_clicked(move |button1| { count.set(count.get()+1); button1.set_label(&count.get().to_string()); }); let window = ApplicationWindow::builder() .application(app) .title("My GTK App") .child(>k_box) .build(); // Present window window.present(); }
Interagire con un widget in piu' callbacks
Si deve clonare il riferimento al widget ogni volta prima di usarlo. Ecco come:
... let label0 = Label::builder() .label("Ciao MOndo") .margin_top(15) .build(); let label_clone = label0.clone(); button0.connect_clicked(move |button0| { count.set(count.get()+1); label_clone.set_label(format!("Hai cliccato {} volte",&count.get().to_string()).as_str()); button0.set_label(&count.get().to_string()); }); let label_clone = label0.clone(); button1.connect_clicked(move |button1| { count.set(count.get()+1); label_clone.set_label(format!("Hai cliccato {} volte",&count.get().to_string()).as_str()); button1.set_label(&count.get().to_string()); });
Come detto clono label0 in label_clone prima di riutilizzarlo.
Altro esempio di interazione
Apro una seconda finestra al click di un Button.
... let window2 = Window::builder() .title("Seconda finestra") .width_request(700) .visible(false) .build(); let button2 = Button::builder().label("Apre seconda finestra").build(); box0.append(&button2); let w2_clone = window2.clone(); button2.connect_clicked(move |_| { w2_clone.present(); }); ...
Intercettare chiusura finestra e cambiare comportamento
window2.connect_close_request(|w| { w.hide(); return glib::Propagation::Stop; });
Modificare i widget da thread esterni al ciclo principale delle Gtk
Per fare questo uso i messaggi. Non modifico i widgets direttamente da altri thread. Dunque sul ciclo principale avro' un timeout che ogni tot di tempo controlla se ci sono messaggi che poi userà per modificare i widget. Uso i classici mpsc::channel.
let (tx, rx) = mpsc::channel::<String>();
Ecco tutto il codice commentato:
use gtk4::prelude::*; use gtk4::{Application, ApplicationWindow, glib, Box,Label,Entry,gio }; use std::sync::mpsc; use std::thread; use std::time::Duration; const APP_ID: &str = "org.gtk_rs.hello"; fn main() -> glib::ExitCode { // Create a new application let app = Application::builder().application_id(APP_ID).build(); // Connect to "activate" signal of `app` app.connect_activate(build_ui); // Run the application app.run() } fn build_ui(app: &Application) { let box0 = Box::builder() .orientation(gtk4::Orientation::Vertical) .build(); let entry0=Entry::builder() .build(); let label = Label::builder() .label("Incrementiamo?") .use_markup(true) .build(); box0.append(&label); box0.append(&entry0); // Siamo nel ciclo principale delle Gtk. Resto in ascolto (polling) // per la ricezine dei messaggi. In questo modo mi evito di modificare // i widgets da altri thread. let (tx, rx) = mpsc::channel::<String>(); glib::timeout_add_local(Duration::from_millis(100), move || { // Legge tutti i messaggi disponibili // Qui si potrebbero filtrare i messaggi per fare cose diverse while let Ok(msg) = rx.try_recv() { let m = msg.clone(); //prima di usare il messaggio lo clono label.set_label(&m); } glib::ControlFlow::Continue }); gio::spawn_blocking(move || { let mut t =0; // Un loop che ogni secondo invia un messaggio con una stringa // al ciclo principale. Il cicloprincipale ha un timeout che ogni // lancia una chiusura per l'elaborazione del messaggio ogni n decimi di secondo loop{ t=t+1; if tx.send(format!("Count: {}", t)).is_err() { break; } let wait_secs = Duration::from_secs(1); thread::sleep(wait_secs); } }); let window = ApplicationWindow::builder() .application(app) .title("My GTK App") .width_request(500) .child(&box0) .build(); // Present window window.present(); }
programmazione/rust/gtkrs/gestione_memoria.txt · Ultima modifica: 12/05/2026 13:50 da Fabio Di Matteo

