Alessio Treglia

everybody lies
  • Quality Assurance
  • EN blog
  • rss
  • Inizio
  • Chi sono
  • pyRisk
  • Roma3 WiFi Authenticator
  • Installation Report Generator
  • Contattami

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 risposte

molto interessante tutto ciò...non è che prima o poi ti

bastianazzo | 8 Luglio 2008 | 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

[Reply]

Sì, l'argomento mi interessa molto, vedrò di trovare del tempo

quadrispro | 8 Luglio 2008 | 11:45

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

[Reply]

Lascia un commento

Puoi usare questi tag : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Click to cancel reply

Chi sono


Per contattarmi mandami una mail

Argomenti

Aggiornamento Ambienti di sviluppo Audio Bug e problemi vari C Cazzate varie Comunità Italiana Documentazione e wiki Feisty Firefox GNOME GTK+ GTK Rm3WiFi Authenticator Guide e howto Gutsy Hardy Installation Report Generator Installazione e problemi all'avvio Intrepid Jaunty Java Kernel e moduli Last.fm Musica Notizie Open source & free software Planet Ubuntu-it Programmazione e sviluppo Python Siti,servizi & blog Società e media Traduzioni Ubuntu Università e scienza Viaggi Video Windows Wordpress Xubuntu

Ultimi commenti

  • Roberto su Ubuntu 9.04, chiamiamola per nome
  • Flavio su Roma3, anche Ingegneria esprime il suo dissenso
  • iced su Si riparte!
  • Fabio su Si riparte!
  • l3on su Si riparte!

Tutti gli articoli

Ubuntu in Italiano

Versione a 32 bit

RSS Planet di Ubuntu-it

  • Flavia Weisghizzi: La Strega e l'Alchimista (Parte 2)
  • Leo Iannacone (l3on): Una piccola patch per Kaffeine…
  • Divilinux: Italia chiama Brasile, Brasile risponde
  • Ubuntu-it Newsletter: Newsletter italiana numero 27
  • Dario Cavedon: E' arrivato il freddo...

Blogroll

  • (LS) Lorenzo Sfarra
  • Bubuntu
  • crisis
  • Dagospia
  • Divilinux Lost Blog
  • Embrace’s Blog
  • Fradeve OpenBlog
  • Il blog di Totò
  • Il mondo di Paolettopn
  • Leo
  • Maurizio Moriconi
  • Milo Casagrande
  • Parzialmente scremato
  • TuxLinux
  • Ubuntu block notes

Licenza

I contenuti di questo sito sono coperti da licenza copyleft Creative Commons


Creative Commons Attribution-ShareAlike 2.5 Italy

Powered links

Il Bloggatore
BlogItalia.it - La directory italiana dei blog
Sfondi Desktop Classifica di siti - Iscrivete il vostro!
eXplicatum - Aggregatore online di Notizie / Blog / Feed RSS

Ascolti recenti

  • Joe Cocker – Feelin Alright
  • Band from TV – You Can't Always Get What You Want
  • Solomon Burke – 10 - None of Us Are Free
  • Jon Cleary – Got to Be More Careful
  • Three Dog Night – One is the Lonliest Number
  • Solomon Burke – 10 - None of Us Are Free
  • Jon Cleary – Got to Be More Careful
  • Band from TV – You Can't Always Get What You Want
  • Massive Attack – Teardrop
  • Joe Cocker – Feelin Alright

RSS alessio and friends on identi.ca

  • alessio: Workin on darcs package
  • alessio: packaging in progress, I think to leave Italian Doc Team seriously
  • milo: socket socket socket! Python socket!
  • alessio: is hungry
  • alessio: trying Simply RSS
  • alessio: feelin' so much tired, going to bed...
  • alessio: feeling s
  • alessio: 's waiting for Vale...
  • alessio: I have to study...
  • milo: fuck telepass.it website... it sucks!

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