Alessio Treglia

everybody lies
  • Quality Assurance
  • EN blog
  • Inizio
  • Chi sono
  • Roma3 WiFi Authenticator
  • Installation Report Generator
  • Preventivi e consulenze

Scrivere un’applicazione in C con le GTK (Seconda parte)

quadrispro | 7 luglio 2008

Dopo una lunga attesa, ecco una nuova puntata del mio breve tutorial alla programmazione con le GTK+! Cercherò di offrirvi una panoramica sufficientemente completa sull’aspetto più importante della programmazione con le librerie GTK+: come associare delle funzioni (dette callbacks) agli eventi scatenati dai widget dell’interfaccia.

Innanzitutto ecco una schermata della nuova interfaccia della nostra piccola applicazione, sicuramente migliore di quella precedente:

La gestione degli eventi

Non mi dilungherò sulla “theory of signals and callbacks“, è un argomento molto complesso che esula dagli scopi di questo articolo, preferisco mostrare il funzionamento del sistema attraverso degli esempi pratici.

Nella funzione create_window(), all’interno del sorgente principale main.c, c’è una riga di codice, accompagnata da un commento che ne sottolinea, giustamente, l’importanza:

/* This is important */
glade_xml_signal_autoconnect (gxml);

Per capire il perchè di tale commento basta leggere cosa dice la documentazione a riguardo:

“This function is a variation of glade_xml_signal_connect. It uses gmodule’s introspective features (by openning the module NULL) to look at the application’s symbol table. From here it tries to match the signal handler names given in the interface description with symbols in the application and connects the signals.”

Libglade Reference Manual

Ciò significa che, mentre la funzione glade_xml_signal_connect() necessita di essere invocata per ogni evento, glade_xml_signal_autoconnect() rappresenta una soluzione automatica più elegante per legare tutti gli eventi scatenati da un widget ai gestori degli stessi.

Apriamo nuovamente il file dell’interfaccia e selezioniamo il pulsante «OK», dunque facciamo clic su «Proprietà»: in «Generale» e assegniamogli un nome secondo le nostre convenzioni preferite (io l’ho chiamato «button_ok»), infine apriamo la scheda «Segnali» e associamo al segnale «clicked» il nome di una callback che andremo a definire (il mio consiglio è di scegliere uno dei nomi presenti nell’elenco di default). Ecco una schermata:

Come assegnare la callback al segnale del widget

Ora possiamo definire il gestore nel file header callbacks.h:

void on_button_on_clicked(GtkWidget * widget, gpointer data);

Prima di implementare la funzione vi mostro quella che, solitamente, è una forma generic per le funzioni callback:

void callback_func( GtkWidget *widget,
             ... /* altri argomenti del segnale */
             gpointer   callback_data );

Il primo argomento è un puntatore al widget (finestra, pulsante, casella di testo, quello-che-è) responsabile dell’emissione del segnale (eggià, si dice proprio così…), l’ultimo è un puntatore alle informazioni passate in g_signal_connect() (se utilizzata).

Prestate attenzione al fatto che non tutte le callbacks hanno la stessa forma (i parametri dipendono dal tipo di segnale), alcune hanno delle forme molto differenti da quella mostrata nel precedente esempio.

Torniamo a noi: cosa dovrà accadere alla pressione del pulsante «OK»? Avevo pensato di stampare nell’area di testo del risultato un riepilogo dei dati inseriti dall’utente, ecco un esempio:

\

Infine, ecco il codice della callback associata all’evento, con i commenti immersi nel codice:

void
on_button_ok_clicked (GtkWidget *widget, gpointer data)
{ 

	GString *gstr = g_string_new(""); /* una stringa di appoggio */
	GtkTextBuffer *buffer; /* il contenuto dell'area di testo */

	buffer = get_textview_result_buffer (); /* inizializziamo il puntatore... */

	/* Procediamo alla formattazione della stringa del risultato... */
	g_string_printf(gstr,
					"Casella di testo: %s\nPulsante numerico: %d\nCaselle di scelta: A: %d B: %d C: %d\nRighe inserite: %d\n",
					(char *)get_entry1_text (),
					(int)get_spinbutton1_value (),
					(int)is_checkbutton1_selected (),
					(int)is_checkbutton2_selected (),
					(int)is_checkbutton3_selected (),
					(int)get_treeview_userinput_rowscount ()
					); 

	gtk_text_buffer_set_text (buffer, gstr->str, -1); /* ...infine aggiorniamo il contenuto. */
}

Per completezza presento anche il codice delle funzioni richiamate dalla callback:

/* file: main.c */

/*
 Restituisce il testo della casella di testo entry1.
*/
const gchar*
get_entry1_text()
{
	GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget (gxml, "entry1"));
	return gtk_entry_get_text(entry);
}

/*
 Restituisce il testo della casella di testo entry1.
*/
const gchar*
get_entry2_text()
{
	GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget (gxml, "entry2"));
	return gtk_entry_get_text(entry);
}

/*
 Restituisce il valore del pulsante numerico.
*/
gint get_spinbutton1_value()
{
	GtkSpinButton *spinbutton1 = (GtkSpinButton *)glade_xml_get_widget (gxml, "spinbutton1");
	return gtk_spin_button_get_value_as_int(spinbutton1);
}

/*
 Verificare che la casella di scelta sia selezionata.
*/
gboolean is_checkbutton1_selected()
{
	GtkCheckButton *checkbutton = (GtkCheckButton *)glade_xml_get_widget (gxml, "checkbutton1");
	return gtk_toggle_button_get_active ((GtkToggleButton *)checkbutton);
}

/*
 Idem
*/
gboolean is_checkbutton2_selected()
{
	GtkCheckButton *checkbutton = (GtkCheckButton *)glade_xml_get_widget (gxml, "checkbutton2");
	return gtk_toggle_button_get_active ((GtkToggleButton *)checkbutton);
}

/*
 Idem
*/
gboolean is_checkbutton3_selected()
{
	GtkCheckButton *checkbutton = (GtkCheckButton *)glade_xml_get_widget (gxml, "checkbutton3");
	return gtk_toggle_button_get_active ((GtkToggleButton *)checkbutton);
}

/*
 Conta il numero delle righe della vista ad albero.
*/
int
get_treeview_userinput_rowscount ()
{
	GtkTreeStore *store; /* puntatore al modello dei dati */
	GtkTreeIter iter; /* iteratore */
	int n = 0; /* numero delle righe */ 

	/* preleva il modello dalla vista ad albero */
	store = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview_userinput));

	/* inizializza l'iteratore con il primo elemento del modello */
	if(gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
		n+=1; /* nuova riga */
		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter) )
			/* incrementa il contatore finchè è presente
			 un altro elemento */
			n+=1;
	}

	return n; /* restituisce il numero di righe */
}

/*
 Restituisce un puntatore al buffer della casella
 del risultato.
*/
GtkTextBuffer *
get_textview_result_buffer ()
{
	return gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview_result));
}

Il meccanismo può risultare non proprio immediato, ma una volta imparate le nozioni fondamentali, il resto viene tutto da sè, basta avere la pazienza di sfogliarsi la documentazione (povera solo di buoni esempi di codice) e studiarsi le funzioni necessarie ai propri scopi.

Concludo allegandovi il codice del progetto e rinnovandovi l’appuntamento alla prossima puntata, nella quale adotteremo una strategia per l’internazionalizzazione del nostro programmino.

Categorie
Ambienti di sviluppo, C, GNOME, GTK+, Guide e howto
Commenti RSS
Commenti RSS
Trackback
Trackback

« Una nuova macro per il wiki di Ubuntu-it Planet Ubuntu-it, da oggi è “restricted” »

2 Responses to “Scrivere un’applicazione in C con le GTK (Seconda parte)”

  1. bastianazzo scrive:
    8 luglio 2008 alle 07:35

    molto interessante tutto ciò…non è che prima o poi ti dedicherai anche alle gtkmm e alle applicazioni GTK in C++? sarebbe davvero fantastico :)

    molte grazie

    Replica
  2. quadrispro scrive:
    8 luglio 2008 alle 11:45

    Sì, l’argomento mi interessa molto, vedrò di trovare del tempo :D

    Replica

Leave a Reply

Fare clic per cancellare la replica.

Chi sono

Se volete contattarmi, potete utilizzare l'apposito form.

Powered by Netsons

Google Friend Connect

Argomenti

Acer Aspire One Aggiornamento Ambienti di sviluppo Arte,libri & Cultura Audio Bug e problemi vari C Compiz Fusion Comunità internazionale Comunità Italiana Cose varie Debian Documentazione e wiki Esperienze Feisty Firefox GNOME GTK+ GTK Rm3WiFi Authenticator Guide e howto Gutsy Hardy Iniziative Installation Report Generator Installazione e problemi all'avvio Intrepid Jaunty Java Karmic Kernel e moduli Last.fm Linpus Lucid MSI U90 Musica Netbook Remix Notizie ONDA MT503HSA Open source & free software Planet Ubuntu-it Programmazione e sviluppo Python Siti,servizi & blog Società e media Traduzioni Ubuntu Ubuntu Developer Summit Università e scienza Viaggi Video Windows Wordpress Xfce Xubuntu

Ultimi commenti

  • Luciano Krostag su Lo sviluppo di Installation Report Generator, il merge di gtk2hs, Universe Contributor Application, e….
  • Pixel su Cinque fantastici ricordi di Londra
  • quadrispro su Ubuntu aiuta a diffondere i virus per Windows
  • gigi su Ubuntu aiuta a diffondere i virus per Windows
  • DarkJackAho su Windows 7, un silenzioso terrorista

Tutti gli articoli

RSS Planet di Ubuntu-it

  • Divilinux: Linux-2.6.33 – Nvidia driver e brightness Samsung R610
  • Dario Cavedon: Il Governo stanzia i fondi per la "banda larga". Ma li usa per una nave.
  • Dario Cavedon: L'ultimo pandoro di primavera
  • Alessio Treglia (quadrispro): Cinque fantastici ricordi di Londra
  • Ubuntu-it News: Newsletter italiana numero 9

Blogroll

  • (LS) Lorenzo Sfarra
  • Antonio Doldo Linux Blog
  • Bubuntu
  • crisis
  • Dagospia
  • Divilinux Lost Blog
  • Embrace’s Blog
  • Fabrizio Balliano
  • Fradeve OpenBlog
  • Il blog di Totò
  • Il mondo di Paolettopn
  • Leo
  • Maurizio Moriconi
  • Milo Casagrande
  • Palla's Home
  • Parzialmente scremato
  • sottovoce per non svegliare il cane
  • TuxLinux
  • Ubuntu block notes

Accedi o registrati

  • Registrati
  • Collegati
  • Voce RSS
  • RSS dei commenti
  • WordPress.org
rss Commenti RSS valid xhtml 1.1 design by jide powered by Wordpress get firefox