Strumenti Utente

Strumenti Sito


programmazione:rust:gtkrs:gestione_memoria

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(&gtk_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