SlideShare una empresa de Scribd logo
1 de 18
Descargar para leer sin conexión
GUI in Gtk+
     con



   Glade
     &
   Anjuta



            di Stefano Delfino
Lo scopo di questa piccola guida è quello di mostrare come realizzare una semplicissima GUI
utilizzando il linguaggio C e la libreria grafica Gtk+. La guida è stata realizzata utilizzando Ubuntu
10.10 “Maverick Meerkat”. Potrebbero esserci delle lievi differenze tra le varie versioni ma in linea
di massima tutto dovrebbe corrispondere.


1. Installazione
Per cominciare dobbiamo installare la libreria Gtk+ ed altre componenti neccessarie per il progetto.
Installate i seguenti pacchetti assecondando tutte le dipendenze:

           •   build-essential
           •   libgtk2.0-dev
           •   autotools-dev
           •   libtool
           •   intltool
           •   intltool-debian
           •   glade
           •   anjuta

Ora abbiamo tutto ciò che ci serve per creare la nostra piccola GUI. Vogliamo creare una piccola
interfaccia di dialogo che ci permette di fare login mediante l'immissione di username e password;
il controllo delle credenziali inserite sarà fatto su un file di testo, ma noi siamo interessati solo
all'aspetto grafico e non alle varie tecniche di autenticazione degli utenti.
Per prima cosa creiamo un dialogo di richiesta credenziali.




Quella mostrata sopra è la nostra finestra di richiesta credenziali come viene mostrata in Glade a
fine lavoro. Di seguito viene mostrata la finestra di risposta all'autenticazione avvenuta con
successo.
Immaginiamo uno scenario nel quale nella prima finestra inseriamo i dati di accesso e se sono
corretti apparirà la seconda finestra con su scritto l'esito dell'autenticazione positiva.




Ora che abbiamo spiegato cosa vogliamo realizzare iniziamo vedendo i due strumenti principali che
andremo ad utilizzare.


2. Tools
La maggior parte del lavoro consiste nel disegnare la parte grafica. Per velocizzare questo processo
esistono programmi per lo sviluppo rapido delle interfacce grafiche i cosiddetti RAD “Rapid
Application Development”. Questi programmi permettono di disegnare l'interfaccia grafica andando
a costruire la struttura gerarchica che tiene assieme i vari oggetti grafici; oltre a questo permettono
anche di impostare proprietà e comportamento dei vari componenti grafici. Per questa guida
utilizzeremo Glade un programma RAD che ci permetterà di disegnare la nostra interfaccia grafica.
Con questo programma andremo a strutturare le nostre due interfacce di dialogo componendo i vari
oggetti grafici. Il programma crea un file XML che contiene la struttura statica dell'interfaccia,
elencando le componenti e le proprietà definite con Glade. Andiamo a vedere Glade come si
presenta graficamente.
Ispettore




                                                                                     Proprietà




     Tavolozza




Notiamo varie parti in questo programma: una Tavolozza a sinistra, con le componenti che
possiamo trascinare all'interno della nostra GUI; un Ispettore in alto a destra, con la struttura
gerarchica degli oggetti della nostra GUI, per il momento osserviamo che tra i widget vi è solo la
finestra “window” che andremo a creare nei passi successivi; un pannello Proprietà in basso a
destra, sotto l'ispettore, con le proprietà degli oggetti che selezioniamo, attraverso il quale andremo
a modificare dimensioni e caratteristiche delle componenti della nostra GUI.

L'altro programma utilizzato in questa guida è Anjuta DevStudio un IDE “Integrated Development
Environment” per applicazioni C/C++ e GNOME/Gtk+. Questo programma ci permette di creare e
gestire l'intero progetto oltre a darci la possibilità di modificare l'interfaccia grafica direttamente dal
Designer integrato.


3. Concetti teorici
Prima di continuare bisogna introdurre un po' di concetti teorici; verranno solo introdotti gli oggetti
(grafici e non) che utilizzeremo ed è consigliato rileggere questa parte dopo aver completato la
guida.
Per la nostra GUI utilizzeremo l'oggetto grafico GtkWindow che ci permette di racchiudere al suo
interno altri oggetti. I vari oggetti appartengono alla libreria Gtk e sono organizzati in una struttura
gerarchica (potete cercare rapidamente e navigare all'interno della libreria tramite il programma
DevHelp “A developers' help browser for GNOME”).
In particolare distinguiamo diverse tipologie di oggetti:

Containers
oggetti contenitori che servono per contenere e dare struttura alle varie componenti; utilizzeremo
per tale scopo tre differenti oggetti grafici contenitori, GtkVBox, GtkHBox, GtkHButtonBox.
GtkVBox e GtkHBox servono per separare e contenere verticalmente e orizzontalmente i vari
oggetti, mentre GtkHButtonBox serve per contenere e separare orizzontalmente vari bottoni (per
creare una pulsantiera).

Controllo e Visualizzazione
oggetti utili per l'iterazione con l'utente. Tra questi utilizzeremo GtkLabel, GtkEntry, GtkButton.

Oltre agli oggetti citati andremo ad utilizzare un oggetto non grafico GtkBuilder. Questo oggetto ci
permette di descrivere un'interfaccia grafica tramite un file XML che definisce la User Interface. In
altre parole a partire dal file XML, creato e modificato con Glade, è possibile creare un'interfaccia
che ci consente di comunicare con l'oggetto grafico rappresentante la nostra GUI.

Segnali e gestori (callback)
GTK è un toolkit guidato dagli eventi. La nostra GUI rimane in attesa, intrappolata all'interno del
ciclo gtk_main, che qualcosa accada. Quando si ha un evento, come la pressione di un bottone,
verrà emesso il segnale appropriato dal componente grafico “widget” interessato. Per collegare
questo segnale ad un'azione appropriata, dobbiamo predisporre un gestore che catturi il segnale o i
segnali emessi e chiami la funzione corretta. Come vedremo questo viene fatto con l'istruzione:

gint gtk_signal_connect ( Gtk_Object *object,
                          gchar *name,
                          GtkSignalFunc func,
                          gpointer func_data );


L'istruzione riportata prende come primo argomento il widget che emetterà il segnale, come
secondo il nome del segnale che si vuole catturare, come terzo la funzione che verrà invocata per
gestire il segnale, e come ultimo argomento i dati che sono passati al gestore.
Il valore di ritorno di tipo gint è un identificativo di questo gestore. Come si può immaginare ogni
segnale può essere gestito anche con più di una funzione; le funzioni di gestione diverse verranno
eseguite in sequenza. Tramite questo identificatore si ha la possibilità successivamente di rimuovere
questo gestore, e lo si fa tramite il comando:

void gtk_signal_disconnect ( Gtk_Object *object,
                             gint id );


Passando il widget da cui si vuole rimuovere il gestore di segnale e l'identificativo restituito da una
delle funzioni signal_connect, si può rimuovere il gestore di segnale che si desidera dal widget.
Questa gestione dei segnali può essere fatta in modo rapido direttamente in Glade nella scheda
Signals del pannello Propietà. Come vedremo più avanti basta definire solo la funzione di gestione
nel nostro codice, affinché il collegamento segnale/funzione viene fatto in automatico.
4. Creiamo la nostra GUI
In questa parte alterneremo una sequenza di passi utilizzando i due programmi Anjuta e Glade al
fine di realizzare la nostra interfaccia grafica.

Anjuta: creiamo un nuovo progetto.
Aprite il programma Anjuta, e create un nuovo progetto:
   • vi verrà richiesto che tipo di progetto volete creare, selezionate GTK+;
   • date un nome al progetto;
   • selezionate una destinazione per il progetto.

Osserviamo che nella cartella di destinazione data, viene creato il progetto. Per poter lanciare
quanto creato (cioè Execute dal menù run o semplicemente F3) bisogna prima configurare e
generare il progetto.
Generiamo il progetto:
   • dal menù Build premi Build Project (opp. Maiusc+F7): viene richiesto di configurare il
       progetto. Lasciate la voce Configuration selezionata su Debug ed andate avanti premendo
       Execute; (NOTA: se non viene data la possibilità di eseguire Build Project è perché bisogna
       configurare il progetto manualmente tramite la voce Configure Project... sotto il menu
       Build)
   • verranno visualizzati dei messaggi, ed alla fine se tutto è andato correttamente viene
       visualizzato “Completed successfully”.

Notiamo che è stata creata la cartella Debug. Ora lanciamo per la prima volta quanto creato al passo
precedente:
    • dal menù Run premi Execute (opp. F3);
    • apparirà una finestra di nome “window”, e osserviamo anche i messaggi nel Terminale
       dell'IDE;
    • per il momento non preoccupiamoci del warning “Gtk-WARNING” tra poco lo andiamo a
       correggere.

Ora che abbiamo visto per la prima volta la nostra finestra, andiamo a vedere anche dove si trova
nell'area del progetto. In Anjuta, nel riquadro Files, andate a vedere nella cartella src; al suo interno
troviamo diversi file, ma non tutti ci interessano, solo alcuni di questi verranno da noi modificati.

Cominciamo a creare la nostra finestra di richiesta dati; premi con il tasto destro sul file *.ui e
seleziona apri con Disegnatore di interfacce grafiche. Consiglio di non utilizzare il disegnatore
“integrato” con Anjuta, ma quello separato installato e visto in precedenza; lo distinguiamo perché
quello separato si trova sotto la linea nel menù che appare. Se non lo trovate in questo menù è
perché non vi è una associazione tra il file con estensione *.ui e il disegnatore di interfacce grafiche
Glade. Quindi possiamo aprirlo direttamente noi andando tramite Nautilus nella cartella /src del
progetto e premendo col tasto destro, apritelo con Glade. Se abbiamo seguito attentamente e ci
troviamo con quanto detto sopra vediamo apparire Glade con la nostra finestra già caricata.
La figura mostrata in precedenza visualizza quanto detto; il rettangolo al centro è la nostra finestra
creata in automatico nei passi precedenti. Andiamo a modificarla.

Glade: modifica della finestra di richiesta credenziali
Per cominciare selezioniamo la finestra, possiamo farlo sia dall'ispettore che premendo sull'oggetto
stesso.

Nel pannello proprietà sotto la scheda General, andare a modificare i seguenti valori:
   • date un nome Name alla finestra, ad esempio “connectionWindow”;
• impostare un titolo Window Title per la finestra, ad esempio “Autenticazione”;
   • impostare che la finestra non è ridimensionabile Resizable impostato su no;
   • impostare la Posizione nella quale la finestra deve apparire, mettere Centrato;
   • impostare una larghezza e altezza predefinita Default Width e Height: 350 x 220;
Passate alla scheda Common ed impostare:
   • impostare una larghezza e altezza richiesta Request Width e Height: 350 x 220;

Sotto la scheda Signals è possibile impostare i gestori per i segnali che vogliamo gestire; ad
esempio cosa vogliamo fare quando la finestra viene chiusa. La creazione automatica da parte del
programma ha già provveduto per noi ad impostare il gestore destroy() per gestire la chiusura
della finestra; in pratica quando il segnale di distruzione della finestra destroy sotto la voce
GtkObject viene emesso, viene intercettato dal gestore destroy() che troviamo dichiarato e
definito nei file callbacks.*.
Se ricordiamo bene, la prima volta che abbiamo lanciato il programma, abbiamo riscontrato un
“Gtk-WARNING” per via dell'argomento NULL che di default viene passato al gestore;
rimuovetelo in modo da non passare nulla al gestore del segnale. Se volete provate a salvare le
modifiche fatte con Glade e rilanciare da Anjuta il programma (F3) e vedete che il warning è
scomparso. Basta semplicemente fare Execute (F3) che il Build (src) (F7) viene eseguito in
automatico. Noterete che al posto del warning

Gtk­WARNING   **:   Could   not   lookup   object   NULL   on   signal   destroy   of   object 
connectionWindow


è comparso un altro messaggio

Gtk­CRITICAL **: gtk_widget_show: assertion `GTK_IS_WIDGET (widget)' failed


questo perché abbiamo modificato il nome del oggetto finestra da “window” a
“connectionWindow” in Glade; quindi andiamo a modificare nel main (per il momento solo questo)
la linea

window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));


in

window = GTK_WIDGET (gtk_builder_get_object (builder, "connectioWindow"));


Salvando e rilanciando (F3) il tutto notiamo che non ci sono più messaggi. Inoltre notate le
modifiche apportate e cioè la finestra posizionata centralmente, il nome, la dimensione e la non
ridimensionabilità della stessa.

Andiamo ad inserire altri componenti all'interno della finestra.
   • per prima cosa dobbiamo dividere lo spazio in parti orizzontali ne bastano 4; per fare ciò
      prendere l'oggetto Vertical Box (GtkVBox) nella parte “Containers” e metterlo all'interno
      della finestra, selezionare il numero di elementi desiderati Number of items su 4;
   • inserite nei due spazi centrali, due spazi verticali, andando quindi a trascinarvi una
      Horizontal Box (GtkHBox) e selezionando 2 elementi. Il risultato dovrebbe essere questo.
Notate la selezione fatta e nell'ispettore sul GtkVBox e come è impostata la proprietà
Homogeneous. Questa rende gli spazi uguali tra loro, e la impostiamo solo sugli spazi orizzontali e
non su quelli verticali, perché andremo a modificare dinamicamente il contenuto del primo spazio
orizzontale, da una Label con una sola riga di testo ad una con due righe.
Inseriamo altri elementi.
    • prendere una Label (GtkLabel) nella parte “Control and Display” e posizionarla
       all'interno del primo spazio orizzontale;
    • modificate nome ed etichetta alla label, mettendo Name “connectionMessage” e Label
       “Inserisci le credenziali d'accesso”;
    • sempre sulla label impostare Format label - justification a Center;
    • prendere una Horizontal Button Box (GtkHButtonBox) nella parte “Containers” e
       posizionarla all'interno dell'ultimo spazio orizzontale, e selezionare un numero di elementi
       pari a 1;
    • prendere un Button (GtkButton) nella parte “Control and Display” e posizionatelo
       all'interno dell'unico “spazio bottone” della pulsantiera appena creata.
    • modificate nome ed etichetta del bottone, mettendo Name “connectionButton” e Label
       “Connetti”.




Andiamo ora ad inserire la parte relativa alla Username ed alla Password.
   • Inserire due Label negli spazi verticali di sinistra e due Text Entry (GtkEntry) negli spazi
      di destra;
   • modificare la Label delle due Label: quella in alto “Username” e quella in basso
      “Password”;
   • modificate alcune proprietà delle TextEntry appena inserite, in particolare date nome
      “usernameEntry” e “passwordEntry” ed una Maxmum length pari a 30;
•   impostare nella TextEntry passwordEntry la Visibility su NO, questo per mascherare l'input
       con il carattere inserito in Invisible character;

Se provate a lanciare il programma noterete una leggera differenza tra le lunghezze delle
TextEntry/Label corrispondenti; questo è dovuto alla lunghezza delle Label che cambia in base al
proprio contenuto. Andiamo a migliorare questo aspetto estetico:
   • impostare la Width request sotto la scheda Common richiesta delle Label username e
       password a 100;
   • sotto la scheda Packing impostare Expand su NO.

Ora se visualizziamo di nuovo la nostra finestra notiamo che il tutto compare più allineato ed
omogeneo.




Prima di modificare anche i segnali impostati direttamente da Glade, andiamo a vedere un po' il
codice e a fare qualche modifica per collegare qualche segnale emesso dagli oggetti grafici.

Anjuta: cominciamo a modificare il codice
Quello che segue è il codice del main.c così come generato alla creazione del progetto, eccetto che
per la modifica fatta al nome della finestra “connectionWindow”.

#include <gtk/gtk.h>
#include "callbacks.h" 

#define UI_FILE "src/tuorialgtk.ui" 
        
GtkWidget* 
create_window (void) 
{ 
       GtkWidget *window; 
       GtkBuilder *builder; 
       GError* error = NULL; 

       builder = gtk_builder_new (); 
       if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) 
       { 
              g_warning ("Couldn't load builder file: %s", error­>message); 
              g_error_free (error); 
       } 

       /* This is important */ 
       gtk_builder_connect_signals (builder, NULL); 
       window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow")); 
 
        g_object_unref (builder); 
         
        return window; 
} 


int 
main (int argc, char *argv[]) 
{ 
       GtkWidget *window; 

#ifdef ENABLE_NLS 
       bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 
       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF­8"); 
       textdomain (GETTEXT_PACKAGE); 
#endif 

        gtk_set_locale (); 
        gtk_init (&argc, &argv); 

        window = create_window (); 
        gtk_widget_show (window); 

        gtk_main (); 
        return 0; 
}


Cercherò di commentare tutte le parti importanti di questo pezzo di codice.
Per cominciare si include la libreria Gtk.

#include <gtk/gtk.h>


All'interno del main la prima cosa che si fa è l'inizializzazione della libreria per poter utilizzare le
componenti grafiche Gtk.

gtk_init(&argc, &argv);


Viene resa visibile la finestra creata.

gtk_widget_show(window);


Ed infine si entra nel ciclo principale con la funzione:

gtk_main ();


Da questo ciclo si esce quando viene chiamata la funzione gtk_main_quit() che viene chiamata
automaticamente con la chiusura della finestra (lo vediamo più avanti). Vediamo ora la funzione
create_window().
Osserviamo che in questa funzione facciamo uso della nostra finestra disegnata con Glade,
UI_FILE definito sopra #define UI_FILE "src/tuorialgtk.ui". In particolare la utilizziamo
utilizzando un oggetto di tipo GtkBuilder che da definizione è proprio una interfaccia per file
testuali come XML. GtkBuilder è un oggetto ausiliario che legge descrizioni testuali di una
interfaccia utente e istanzia l'oggetto descritto.

I passi principali per riferirci ed utilizzare una interfaccia grafica descritta tramite un file XML sono
i seguenti:
1 ­ builder = gtk_builder_new ()
2 ­ gtk_builder_add_from_file (builder, UI_FILE, &error)) 
3 ­ gtk_builder_connect_signals (builder, NULL)
4 ­ window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow"))
5 ­ g_object_unref (builder)


Per prima cosa si crea un GtkBuilder con il comando gtk_builder_new(); possiamo passare una
descrizione al GtkBuilder, tramite la funzione gtk_builder_add_from_file(). Un altro passo
importante è il collegamento con i segnali. Se nella parte grafica abbiamo dichiarato dei gestori di
risposta a segnali emessi dagli oggetti grafici, come ad esempio il nostro destroy(), per collegarli
alle nostre funzioni di gestione scritte nei file callbacks.* dobbiamo chiamare un metodo
gtk_builder_connect_signal() che quindi mette in corrispondenza i gestori della descrizione
con i relativi gestori.

builder = gtk_builder_new (); 
if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) 
{ 
       ...
} 

/* This is important */ 
gtk_builder_connect_signals (builder, NULL);


Per comprendere meglio l'importanza di questo comando gtk_builder_connect_signal() 
provate a commentarlo e a lanciare il programma. Noterete che la finestra viene distrutta ma il
programma rimane nel ciclo gtk_main() questo avviene perché non vi è un'associazione tra il
segnale emesso dalla finestra quando viene distrutta e la chiamata al nostro gestore destroy() e
quindi alla chiamata gtk_main_quit().


                    1° viene premuto il bottone per chiudere la finestra.

2° l'oggetto grafico connectionWindow ha dichiarato in Glade che vuole gestire
il segnale destroy di GtkObject con il gestore destroy.

3° viene cercato quindi un gestore destroy nel codice, questo grazie al comando
gtk_builder_connect_signals().

                                        4° viene quindi eseguito il comando
                                        gtk_main_quit () che oltre a chiudere la finestra
                                        tramite il gestore delle finestre esce anche dal ciclo gtk_main ().


void 
destroy (GtkWidget *widget, gpointer data) 
{ 
       gtk_main_quit (); 
}


Quella        sopra       riportata        è     la       sequenza          di    passi       eseguita        se   il   comando
gtk_builder_connect_signals() sarebbe decommentato. Quindi al momento di cercare il
gestore destroy() come dichiarato sul file XML *.ui tramite Glade lo si trova correttamente nel
codice eseguito. Mentre se il comando fosse commentato non vi sarebbe un collegamento tra i
gestori dei segnali dichiarati in Glade e le funzioni presenti nel programma e quindi non verrebbe
eseguito il comando gtk_main_quit().

Dopo aver fatto questa prova rimuovete il commento.
Per rendere il programma più leggibile, rinominate il gestore destroy() in my_destroy() sia nei
file callbacks.* e sia in Glade (sotto la linguetta Signals nelle Proprietà dell'oggetto
connectionWindow in corrispondenza del segnale GtkObject – destroy nella colonna Handler).

Con la seguente chiamata è possibile prendere un puntatore ad un oggetto dell'interfaccia grafica
disegnata.

window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow"));


In questo caso prendiamo un riferimento alla nostra finestra “connectionWindow”. Ultimo
importante passo è il comando:

g_object_unref (builder);


Con quest'ultimo ci assicuriamo che quando le referenze a questo oggetto sono diventate nulle,
l'oggetto viene rilasciato, cioè la memoria occupata viene liberata.

Ora proviamo a collegare il nostro gestore rinominato in my_destroy() con il segnale emesso dal
pulsante quando viene premuto. Per fare questo basta andare ad aggiungere nella funzione
create_window() le seguenti istruzioni.

{
       ...

GtkWidget *connectionButton; 

       ...
        
connectionButton = GTK_WIDGET (gtk_builder_get_object (builder,"connectionButton")); 

gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked", 
                    GTK_SIGNAL_FUNC (my_destroy), NULL); 

       ...
}

Prendiamo un riferimento al bottone e colleghiamo tramite la funzione gtk_signal_connect(), il
segnale emesso dal bottone quando viene premuto, al nostro gestore. Notate il cast a GTK_OBJECT 
(connectionButton), il segnale “clicked” emesso dal precedente oggetto, e il nome del gestore
con il relativo cast GTK_SIGNAL_FUNC (my_destroy). In questo modo la nostra finestra si chiuderà
quando viene premuto il tasto “Connetti”. Salvate e lanciate
il tutto e osservate se funziona.
In questo esempio abbiamo visto come collegare
dinamicamente con gtk_signal_connect()  un segnale al
suo gestore. Nota che era possibile farlo anche da Glade
andando a dichiarare my_destroy() come gestore per
l'evento clicked di GtkButton, come mostrato in figura, ed
omettendo quanto sopra.

Ora andiamo a collegare l'evento “bottone premuto” ad un
gestore che ci stampa nel terminale le credenziali inserite;
questo per mostrare la creazione di un nuovo gestore e come
reperire i dati inseriti.
Per prima cosa dobbiamo aggiungere la dichiarazione e
definizione di un gestore che chiameremo check_data().
// nel file callback.h

void check_data (GtkWidget *widget, gpointer data);


// nel file callbacks.c

void check_data (GtkWidget *widget, gpointer data) 
{
       printf(“FACCIO QUALCOSA!! n”);
}


Una volta inserito il nostro nuovo gestore lo colleghiamo al segnale “clicked” del nostro bottone.

// nel file main.c

gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked", 
                    GTK_SIGNAL_FUNC (check_data), NULL);


Ora quando premiamo il bottone osserviamo la stampa nel Terminale.
Per prendere il contenuto inserito nelle GtkEntry dobbiamo prendere dei riferimenti agli oggetti
“usernameEntry” e “passwordEntry”. Per fare ciò abbiamo bisogno del nostro oggetto GtkBuilder.
Possiamo procedere in diversi modi. Possiamo dichiarare il puntatore GtkBuider invece che nel
metodo create_window nel nostro main() o come variabile globale; dobbiamo inoltre stare attenti
all'istruzione g_object_unref(builder)  che renderebbe inutilizzabile la variabile. Ecco cosa
faremo:
     • dichiariamo la variabile GtkBuilder *builder nel main;
     • spostiamo l'istruzione g_object_unref (builder)  all'uscita dal gtk_main() quindi alla
         fine del nostro main();
     • spostiamo l'istruzione builder = gtk_builder_new()  nel main prima della chiamata a
         create_window();
     • passiamo il puntatore builder al metodo create_window (GtkBuilder *builder) {};

All'interno del gestore check_data() abbiamo bisogno del riferimento al nostro builder, per
collegarci alla descrizione XML fatta con Glade e quindi prendere i riferimenti ai dati inseriti. Per
fare ciò è possibile passare questo riferimento al nostro gestore al momento della connessione del
segnale con esso. Più precisamente quando utilizziamo gtk_signal_connect() nella funzione
create_window().

gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked", 
                    GTK_SIGNAL_FUNC (check_data), builder);


Il nostro gestore sarà quindi in grado di referenziale tramite l'oggetto GtkBuilder le nostre due
GtkEntry e prenderne il contenuto.

void 
check_data (GtkWidget *widget, gpointer data) 
{ 

       GtkWidget *username = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                                        "usernameEntry")); 
       GtkWidget *password = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                                        "passwordEntry")); 
        
       gchar *usernameInput = gtk_entry_get_text(GTK_ENTRY(username)); 
       gchar *passwordInput = gtk_entry_get_text(GTK_ENTRY(password)); 
        
printf("Username: %s Password: %s n", usernameInput, passwordInput); 
}


Nelle prime due istruzione vado a prendere i puntatori agli oggetti GtkEntry e nelle seguenti due ne
vado a prendere il contenuto testuale. Notate il cast fatto sulla variabile “data” da gpointer a
GTK_BUILDER (NB: funziona anche senza cast).
Andremo ora a simulare l'autenticazione su un file di testo contente le credenziali di accesso. Create
un file “account.txt” e posizionatelo nella stessa directory del progetto *.anjuta. Scrivete nel file
alcune credenziali nella forma:

       username1 password1
       username2 password2
       ...

...

FILE *fp;

if ((fp = fopen("account.txt", "r")) == NULL) { 

               printf("ERRORE fopen R"); 
               exit(1); 
        } 

char user[30]; 
char pass[30]; 

int trovato = 0;
        
while (fscanf(fp,"%s %s", user, pass) != EOF ) { 

        if ( (strcmp(user,usernameInput) == 0) && (strcmp(pass,passwordInput) == 0) ) { 

               printf(“AUTENTICATO n”);
               trovato = 1;  
        }
} 

fclose(fp);

if (trovato == 0) {

        printf(“NON AUTENTICATO n”);
}


Nel pezzo di codice riportato sopra si mostra la semplice gestione di un File testuale dalla sua
lettura al confronto con il testo Username e Password inseriti sopra. La variabile “trovato” ci
permette di uscire appena viene trovata una corrispondenza all'interno del file. Possiamo inserire
questo codice all'interno del gestore check_data() subito dopo le due istruzioni
gtk_entry_get_text().

Modifichiamo il codice per gestire il risultato dell'autenticazione nella GUI.
Se i dati inseriti non sono “corretti” modifichiamo la label “Inserisci le credenziali d'accesso” in
“ATTENZIONE!!nInserire i dati correttamente”, cancellando il testo inserito nelle due Entry. Di
seguito le istruzioni da inserire al posto della stampa “NON AUTENTICATO”.

GtkLabel *connectionMessage = GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),
                                        "connectionMessage")); 
gtk_label_set_text(connectionMessage,"Attenzione!!nInserire i dati correttamente");
gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),
                              "usernameEntry")),""); 
gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),
                              "passwordEntry")),"");


Per prima cosa, prendiamo il riferimento alla Label contenente il messaggio di intestazione della
finestra, cioè “connectionMessage”, e poi ne modifichiamo il testo utilizzando la funzione
gtk_label_set_text() e cancelliamo l'eventuale testo inserito con gtk_entry_set_text().

A questo punto possiamo vedere lanciando il programma, che se i dati sono errati viene mostrata
una label con un testo differente e vengono cancellati i dati inseriti. Mentre se i dati sono corretti
viene stampato su terminale “AUTENTICATO” e viene ripresentata la finestra da capo. Noi a
questo punto vogliamo mostrare il risultato “AUTENTICATO” su un'altra finestra per comunicarlo
all'utente. Per cominciare andiamo a creare la nuova finestra, disegnandola con Glade.

Glade: creiamo la finestra risultato
Andando a modificare il nostro file *.ui, aggiungiamo una finestra. Basta premere sull'oggetto
Window nella Tavolozza, tra i Toplevels. Poi:
   • date alla finestra le stesse proprietà della precedente: altezza e larghezza, posizione,
      ridimensionabilità;
   • dategli un nome “resultWindow” ed un titolo “Risultato”;
   • dichiarate il gestore “my_destroy” per la distruzione della finestra;
   • inserite all'interno della finestra una Label con nome “resultMessage” (l'etichetta non
      importa andiamo a modificarla prima di visualizzare la finestra);
   • sempre sulla label impostare Format label - justification a Center;




Salvate il file con Glade e passiamo a modificare di nuovo il codice.

Anjuta: collegare la finestra risultato
Se l'autenticazione ha un esito positivo allora facciamo le seguenti cose:
    • settiamo la label della finestra di risultato dopo aver recuperato un riferimento ad essa;
    • visualizziamo la finestra risultato e nascondiamo quella di connessione.

Quindi al posto dell'istruzione printf(“AUTENTICATO n”) inseriamo le seguenti istruzioni.

GtkWidget *resultWindow;

resultWindow = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data), "resultWindow")); 

gtk_label_set_text(GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),
                             "resultMessage")),"Autenticazione OK"); 

gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                             "connectionWindow")));               
gtk_widget_show (resultWindow);


A questo punto abbiamo analizzato tutto il codice utile al nostro scopo. Di seguito si riporta
integralmente le parti significative del codice dei vari file.

Main.c

#include "callbacks.h"
#define UI_FILE "src/tuorialgtk.ui" 
        
GtkWidget* 
create_window (GtkBuilder *builder) 
{ 
       GtkWidget *window; 
       GtkWidget *connectionButton; 

         GError* error = NULL; 

         if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) 
         { 
                g_warning ("Couldn't load builder file: %s", error­>message); 
                g_error_free (error); 
         } 

       /* This is important */ 
       gtk_builder_connect_signals (builder, NULL); 
       window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow")); 
        
       connectionButton = GTK_WIDGET (gtk_builder_get_object (builder,
                                  "connectionButton")); 
       gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked", 
                           GTK_SIGNAL_FUNC (check_data), builder); 
        
       return window; 
} 


int 
main (int argc, char *argv[]) 
{ 
       GtkWidget *window; 
       GtkBuilder *builder; 

#ifdef ENABLE_NLS 
       bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 
       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF­8"); 
       textdomain (GETTEXT_PACKAGE); 
#endif 

         gtk_set_locale (); 
         gtk_init (&argc, &argv); 

         builder = gtk_builder_new (); 
          
         window = create_window (builder); 
         gtk_widget_show (window); 

         gtk_main (); 
          
         g_object_unref (builder); 
         return 0; 
}
Callbacks.h

#include <gtk/gtk.h> 

void my_destroy (GtkWidget *widget, gpointer data); 
void check_data (GtkWidget *widget, gpointer data);


Callbacks.c

#include "callbacks.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void 
my_destroy (GtkWidget *widget, gpointer data) 
{ 
       gtk_main_quit (); 
} 

void 
check_data (GtkWidget *widget, gpointer data) 
{ 

       GtkWidget *resultWindow; 
       GtkWidget *username = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                                        "usernameEntry")); 
       GtkWidget *password = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                                        "passwordEntry")); 
        
       gchar *usernameInput = gtk_entry_get_text(GTK_ENTRY(username)); 
       gchar *passwordInput = gtk_entry_get_text(GTK_ENTRY(password)); 

       FILE *fp; 
        
       if ((fp = fopen("account.txt", "r")) == NULL) { 

               printf("ERRORE fopen R"); 
               exit(1); 
       } 

       char user[30]; 
       char pass[30]; 
       int trovato = 0; 
        
       while ( fscanf(fp,"%s %s", user, pass) != EOF) { 

          if ( (strcmp(user,usernameInput) == 0) && 
                  (strcmp(pass,passwordInput) == 0) ) { 

              resultWindow = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                              "resultWindow")); 
              gtk_label_set_text(GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),
                              "resultMessage")),"Autenticazione OK"); 
                      
              gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),
                              "connectionWindow")));               
              gtk_widget_show (resultWindow); 

               trovato = 1; 
          } 
       } 

       fclose(fp); 

       if (trovato == 0) { 
GtkLabel *connectionMessage = GTK_LABEL(gtk_builder_get_object
                                           (GTK_BUILDER(data), "connectionMessage")); 
             gtk_label_set_text(connectionMessage,"Attenzione!!nInserire i dati
                                                                       correttamente"); 

             gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),
                                           "usernameEntry")),""); 
             gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),
                                           "passwordEntry")),""); 
                     
       } 
}


Risorse
Importanti risorse dove trovare altra documentazione sono:
   • http://www.micahcarrick.com/gtk-programming/
   • http://library.gnome.org/devel/gtk-tutorial/stable/
   • http://tadeboro.blogspot.com/2009/09/glade3-tutorial-1-introduction.html
   • http://www.hds619.net/blog/guida-gtk-a-puntate/
   • http://anjuta.org/
   • http://glade.gnome.org/

Más contenido relacionado

La actualidad más candente

Qt Lezione3: un visualizzatore di immagini
Qt Lezione3: un visualizzatore di immaginiQt Lezione3: un visualizzatore di immagini
Qt Lezione3: un visualizzatore di immaginiPaolo Sereno
 
Qt Lezione0: uso del C++ per scrivere applicazioni Qt
Qt Lezione0: uso del C++ per scrivere applicazioni QtQt Lezione0: uso del C++ per scrivere applicazioni Qt
Qt Lezione0: uso del C++ per scrivere applicazioni QtPaolo Sereno
 
Introduzione alla programmazione Android - Android@tulug lezione 4
Introduzione alla programmazione Android - Android@tulug lezione 4Introduzione alla programmazione Android - Android@tulug lezione 4
Introduzione alla programmazione Android - Android@tulug lezione 4Ivan Gualandri
 
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passi
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passiQt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passi
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passiPaolo Sereno
 
Introduzione alla programmazione android - Android@tulug lezione 3
Introduzione alla programmazione android - Android@tulug lezione 3Introduzione alla programmazione android - Android@tulug lezione 3
Introduzione alla programmazione android - Android@tulug lezione 3Ivan Gualandri
 
Qt Lezione1: Creare una dialog Window con Qt Creator in 10 semplici passi
Qt Lezione1: Creare una dialog Window con Qt Creator  in 10 semplici passiQt Lezione1: Creare una dialog Window con Qt Creator  in 10 semplici passi
Qt Lezione1: Creare una dialog Window con Qt Creator in 10 semplici passiPaolo Sereno
 
Che cosa è il Qt Framework
Che cosa è il Qt FrameworkChe cosa è il Qt Framework
Che cosa è il Qt FrameworkPaolo Sereno
 
Introduzione alla programmazione Android - Android@tulug
Introduzione alla programmazione Android - Android@tulugIntroduzione alla programmazione Android - Android@tulug
Introduzione alla programmazione Android - Android@tulugIvan Gualandri
 
Introduzione alla programmazione android - Android@tulug lezione 2
Introduzione alla programmazione android - Android@tulug lezione 2Introduzione alla programmazione android - Android@tulug lezione 2
Introduzione alla programmazione android - Android@tulug lezione 2Ivan Gualandri
 
Installazione Qt/Qt Quick per target Android
Installazione Qt/Qt Quick  per target AndroidInstallazione Qt/Qt Quick  per target Android
Installazione Qt/Qt Quick per target AndroidPaolo Sereno
 
Programmazione mobile: ANDROID
Programmazione mobile: ANDROIDProgrammazione mobile: ANDROID
Programmazione mobile: ANDROIDPaolo Tosato
 
Programmazione mobile: ANDROID
Programmazione mobile: ANDROIDProgrammazione mobile: ANDROID
Programmazione mobile: ANDROIDPaolo Tosato
 
Installazione Qt 4.5.3 per Ms Windows
Installazione Qt 4.5.3 per Ms WindowsInstallazione Qt 4.5.3 per Ms Windows
Installazione Qt 4.5.3 per Ms WindowsPaolo Sereno
 
Ubuntu Touch: Sviluppo App e Convergenza
Ubuntu Touch: Sviluppo App e ConvergenzaUbuntu Touch: Sviluppo App e Convergenza
Ubuntu Touch: Sviluppo App e ConvergenzaGiulio Collura
 
Javascript Camp - Listener Per Eventi
Javascript Camp - Listener Per EventiJavascript Camp - Listener Per Eventi
Javascript Camp - Listener Per EventiSimone Gentili
 

La actualidad más candente (17)

Qt Lezione3: un visualizzatore di immagini
Qt Lezione3: un visualizzatore di immaginiQt Lezione3: un visualizzatore di immagini
Qt Lezione3: un visualizzatore di immagini
 
Qt Lezione0: uso del C++ per scrivere applicazioni Qt
Qt Lezione0: uso del C++ per scrivere applicazioni QtQt Lezione0: uso del C++ per scrivere applicazioni Qt
Qt Lezione0: uso del C++ per scrivere applicazioni Qt
 
Introduzione alla programmazione Android - Android@tulug lezione 4
Introduzione alla programmazione Android - Android@tulug lezione 4Introduzione alla programmazione Android - Android@tulug lezione 4
Introduzione alla programmazione Android - Android@tulug lezione 4
 
Qt Lezione6
Qt Lezione6Qt Lezione6
Qt Lezione6
 
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passi
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passiQt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passi
Qt Lezione2: Creare un’applicazione con Qt Creator in pochi semplici passi
 
Introduzione alla programmazione android - Android@tulug lezione 3
Introduzione alla programmazione android - Android@tulug lezione 3Introduzione alla programmazione android - Android@tulug lezione 3
Introduzione alla programmazione android - Android@tulug lezione 3
 
Qt Lezione1: Creare una dialog Window con Qt Creator in 10 semplici passi
Qt Lezione1: Creare una dialog Window con Qt Creator  in 10 semplici passiQt Lezione1: Creare una dialog Window con Qt Creator  in 10 semplici passi
Qt Lezione1: Creare una dialog Window con Qt Creator in 10 semplici passi
 
Che cosa è il Qt Framework
Che cosa è il Qt FrameworkChe cosa è il Qt Framework
Che cosa è il Qt Framework
 
Introduzione alla programmazione Android - Android@tulug
Introduzione alla programmazione Android - Android@tulugIntroduzione alla programmazione Android - Android@tulug
Introduzione alla programmazione Android - Android@tulug
 
Introduzione alla programmazione android - Android@tulug lezione 2
Introduzione alla programmazione android - Android@tulug lezione 2Introduzione alla programmazione android - Android@tulug lezione 2
Introduzione alla programmazione android - Android@tulug lezione 2
 
Installazione Qt/Qt Quick per target Android
Installazione Qt/Qt Quick  per target AndroidInstallazione Qt/Qt Quick  per target Android
Installazione Qt/Qt Quick per target Android
 
Programmazione mobile: ANDROID
Programmazione mobile: ANDROIDProgrammazione mobile: ANDROID
Programmazione mobile: ANDROID
 
Programmazione mobile: ANDROID
Programmazione mobile: ANDROIDProgrammazione mobile: ANDROID
Programmazione mobile: ANDROID
 
Introduzione a Latex
Introduzione a LatexIntroduzione a Latex
Introduzione a Latex
 
Installazione Qt 4.5.3 per Ms Windows
Installazione Qt 4.5.3 per Ms WindowsInstallazione Qt 4.5.3 per Ms Windows
Installazione Qt 4.5.3 per Ms Windows
 
Ubuntu Touch: Sviluppo App e Convergenza
Ubuntu Touch: Sviluppo App e ConvergenzaUbuntu Touch: Sviluppo App e Convergenza
Ubuntu Touch: Sviluppo App e Convergenza
 
Javascript Camp - Listener Per Eventi
Javascript Camp - Listener Per EventiJavascript Camp - Listener Per Eventi
Javascript Camp - Listener Per Eventi
 

Destacado

Gtk development-using-glade-3
Gtk development-using-glade-3Gtk development-using-glade-3
Gtk development-using-glade-3caezsar
 
Taller Python Gtk Glade
Taller Python Gtk GladeTaller Python Gtk Glade
Taller Python Gtk Gladecampus party
 
Presentación de glade
Presentación de gladePresentación de glade
Presentación de gladejorgiux97
 
Qt roadmap: the future of Qt
Qt roadmap: the future of QtQt roadmap: the future of Qt
Qt roadmap: the future of QtDeveler S.r.l.
 
Qt Creator: the secret weapon of any c++ programmer
Qt Creator: the secret weapon of any c++ programmerQt Creator: the secret weapon of any c++ programmer
Qt Creator: the secret weapon of any c++ programmerDeveler S.r.l.
 
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linux
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linuxTrace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linux
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linuxDeveler S.r.l.
 
Integrazione QML / C++
Integrazione QML / C++Integrazione QML / C++
Integrazione QML / C++Paolo Sereno
 
Javascript in Linux Desktop
Javascript in Linux DesktopJavascript in Linux Desktop
Javascript in Linux DesktopYuren Ju
 
GUI Programming with Perl / GTK
GUI Programming with Perl / GTKGUI Programming with Perl / GTK
GUI Programming with Perl / GTKAnuradha Weeraman
 
Integrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsIntegrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsNathan Yergler
 
Linux Kernel Development
Linux Kernel DevelopmentLinux Kernel Development
Linux Kernel DevelopmentPriyank Kapadia
 
Introduction to c programming
Introduction to c programmingIntroduction to c programming
Introduction to c programmingManoj Tyagi
 

Destacado (13)

Gtk development-using-glade-3
Gtk development-using-glade-3Gtk development-using-glade-3
Gtk development-using-glade-3
 
G T K+ 101
G T K+ 101G T K+ 101
G T K+ 101
 
Taller Python Gtk Glade
Taller Python Gtk GladeTaller Python Gtk Glade
Taller Python Gtk Glade
 
Presentación de glade
Presentación de gladePresentación de glade
Presentación de glade
 
Qt roadmap: the future of Qt
Qt roadmap: the future of QtQt roadmap: the future of Qt
Qt roadmap: the future of Qt
 
Qt Creator: the secret weapon of any c++ programmer
Qt Creator: the secret weapon of any c++ programmerQt Creator: the secret weapon of any c++ programmer
Qt Creator: the secret weapon of any c++ programmer
 
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linux
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linuxTrace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linux
Trace32 lo-strumento-piu-completo-per-il-debug-di-un-sistema-linux
 
Integrazione QML / C++
Integrazione QML / C++Integrazione QML / C++
Integrazione QML / C++
 
Javascript in Linux Desktop
Javascript in Linux DesktopJavascript in Linux Desktop
Javascript in Linux Desktop
 
GUI Programming with Perl / GTK
GUI Programming with Perl / GTKGUI Programming with Perl / GTK
GUI Programming with Perl / GTK
 
Integrating CC Licensing with Applications
Integrating CC Licensing with ApplicationsIntegrating CC Licensing with Applications
Integrating CC Licensing with Applications
 
Linux Kernel Development
Linux Kernel DevelopmentLinux Kernel Development
Linux Kernel Development
 
Introduction to c programming
Introduction to c programmingIntroduction to c programming
Introduction to c programming
 

Similar a GUI in Gtk+ con Glade & Anjuta

Development process
Development processDevelopment process
Development processEmidio Croci
 
Qt Lezione5: Layout management e Qt Designer
Qt Lezione5: Layout management e Qt DesignerQt Lezione5: Layout management e Qt Designer
Qt Lezione5: Layout management e Qt DesignerPaolo Sereno
 
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...Aruba S.p.A.
 
Sviluppo Di Applicazioni Su I Os
Sviluppo Di Applicazioni Su I OsSviluppo Di Applicazioni Su I Os
Sviluppo Di Applicazioni Su I OsNoDelay Software
 
Exploring VS Code
Exploring VS CodeExploring VS Code
Exploring VS Codedotnetcode
 
Arduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'AmbrosioArduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'Ambrosiofirenze-gtug
 
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...Antonio Gallo
 
Preparazione materiale web
Preparazione materiale webPreparazione materiale web
Preparazione materiale webalyalethebest
 
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0Studio e sviluppo di un’interfaccia per applicazione WEB 2.0
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0NobelMusic
 
Progettazione per Apple Watch - Todi Appy Days 2015
Progettazione per Apple Watch - Todi Appy Days 2015Progettazione per Apple Watch - Todi Appy Days 2015
Progettazione per Apple Watch - Todi Appy Days 2015Todi Appy Days
 
Wearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchWearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchPaolo Musolino
 
Csp@scuola smarttv corso1
Csp@scuola smarttv corso1Csp@scuola smarttv corso1
Csp@scuola smarttv corso1CSP Scarl
 
Public #Android #Material-Design #italian
Public #Android #Material-Design #italianPublic #Android #Material-Design #italian
Public #Android #Material-Design #italianNicolas Bortolotti
 
Meetup ASP.NET Core Angular
Meetup ASP.NET Core AngularMeetup ASP.NET Core Angular
Meetup ASP.NET Core Angulardotnetcode
 
Ttg 09 07_2015_debug_vs_2015
Ttg 09 07_2015_debug_vs_2015Ttg 09 07_2015_debug_vs_2015
Ttg 09 07_2015_debug_vs_2015Piero Sbressa
 
MobileDevCamp2012 - Android
MobileDevCamp2012 - AndroidMobileDevCamp2012 - Android
MobileDevCamp2012 - Androidmobiledevcamp
 

Similar a GUI in Gtk+ con Glade & Anjuta (20)

La tua prima app per Ubuntu Touch
La tua prima app per Ubuntu TouchLa tua prima app per Ubuntu Touch
La tua prima app per Ubuntu Touch
 
Development process
Development processDevelopment process
Development process
 
Qt Lezione5: Layout management e Qt Designer
Qt Lezione5: Layout management e Qt DesignerQt Lezione5: Layout management e Qt Designer
Qt Lezione5: Layout management e Qt Designer
 
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...
Con Aruba, a lezione di cloud #lezione 29: 'GitLab e Cloud Server Smart - Ins...
 
Sviluppo Di Applicazioni Su I Os
Sviluppo Di Applicazioni Su I OsSviluppo Di Applicazioni Su I Os
Sviluppo Di Applicazioni Su I Os
 
2007 Py05 gtk
2007 Py05 gtk2007 Py05 gtk
2007 Py05 gtk
 
Exploring VS Code
Exploring VS CodeExploring VS Code
Exploring VS Code
 
Arduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'AmbrosioArduino - Massimiliano D'Ambrosio
Arduino - Massimiliano D'Ambrosio
 
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...
Le novità di Ionic 4- Il framework basato su Angular per sviluppare applicazi...
 
Preparazione materiale web
Preparazione materiale webPreparazione materiale web
Preparazione materiale web
 
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0Studio e sviluppo di un’interfaccia per applicazione WEB 2.0
Studio e sviluppo di un’interfaccia per applicazione WEB 2.0
 
Progettazione per Apple Watch - Todi Appy Days 2015
Progettazione per Apple Watch - Todi Appy Days 2015Progettazione per Apple Watch - Todi Appy Days 2015
Progettazione per Apple Watch - Todi Appy Days 2015
 
Wearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple WatchWearable Lab: Progettazione per Apple Watch
Wearable Lab: Progettazione per Apple Watch
 
Csp@scuola smarttv corso1
Csp@scuola smarttv corso1Csp@scuola smarttv corso1
Csp@scuola smarttv corso1
 
Public #Android #Material-Design #italian
Public #Android #Material-Design #italianPublic #Android #Material-Design #italian
Public #Android #Material-Design #italian
 
Meetup ASP.NET Core Angular
Meetup ASP.NET Core AngularMeetup ASP.NET Core Angular
Meetup ASP.NET Core Angular
 
Basta un Click!
Basta un Click!Basta un Click!
Basta un Click!
 
#dd12 grillo daniele_xpages_tips_tricks_rev2
#dd12 grillo daniele_xpages_tips_tricks_rev2#dd12 grillo daniele_xpages_tips_tricks_rev2
#dd12 grillo daniele_xpages_tips_tricks_rev2
 
Ttg 09 07_2015_debug_vs_2015
Ttg 09 07_2015_debug_vs_2015Ttg 09 07_2015_debug_vs_2015
Ttg 09 07_2015_debug_vs_2015
 
MobileDevCamp2012 - Android
MobileDevCamp2012 - AndroidMobileDevCamp2012 - Android
MobileDevCamp2012 - Android
 

Último

Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...
Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...
Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...Associazione Digital Days
 
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...Associazione Digital Days
 
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...Associazione Digital Days
 
ScrapeGraphAI: a new way to scrape context with AI
ScrapeGraphAI: a new way to scrape context with AIScrapeGraphAI: a new way to scrape context with AI
ScrapeGraphAI: a new way to scrape context with AIinfogdgmi
 
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...Associazione Digital Days
 
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”Associazione Digital Days
 

Último (6)

Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...
Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...
Federico Bottino, Lead Venture Builder – “Riflessioni sull’Innovazione: La Cu...
 
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
Daniele Lunassi, CEO & Head of Design @Eye Studios – “Creare prodotti e servi...
 
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...
Alessio Mazzotti, Aaron Brancotti; Writer, Screenwriter, Director, UX, Autore...
 
ScrapeGraphAI: a new way to scrape context with AI
ScrapeGraphAI: a new way to scrape context with AIScrapeGraphAI: a new way to scrape context with AI
ScrapeGraphAI: a new way to scrape context with AI
 
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...
Luigi Di Carlo, CEO & Founder @Evometrika srl – “Ruolo della computer vision ...
 
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”
Edoardo Di Pietro – “Virtual Influencer vs Umano: Rubiamo il lavoro all’AI”
 

GUI in Gtk+ con Glade & Anjuta

  • 1. GUI in Gtk+ con Glade & Anjuta di Stefano Delfino
  • 2. Lo scopo di questa piccola guida è quello di mostrare come realizzare una semplicissima GUI utilizzando il linguaggio C e la libreria grafica Gtk+. La guida è stata realizzata utilizzando Ubuntu 10.10 “Maverick Meerkat”. Potrebbero esserci delle lievi differenze tra le varie versioni ma in linea di massima tutto dovrebbe corrispondere. 1. Installazione Per cominciare dobbiamo installare la libreria Gtk+ ed altre componenti neccessarie per il progetto. Installate i seguenti pacchetti assecondando tutte le dipendenze: • build-essential • libgtk2.0-dev • autotools-dev • libtool • intltool • intltool-debian • glade • anjuta Ora abbiamo tutto ciò che ci serve per creare la nostra piccola GUI. Vogliamo creare una piccola interfaccia di dialogo che ci permette di fare login mediante l'immissione di username e password; il controllo delle credenziali inserite sarà fatto su un file di testo, ma noi siamo interessati solo all'aspetto grafico e non alle varie tecniche di autenticazione degli utenti. Per prima cosa creiamo un dialogo di richiesta credenziali. Quella mostrata sopra è la nostra finestra di richiesta credenziali come viene mostrata in Glade a fine lavoro. Di seguito viene mostrata la finestra di risposta all'autenticazione avvenuta con successo.
  • 3. Immaginiamo uno scenario nel quale nella prima finestra inseriamo i dati di accesso e se sono corretti apparirà la seconda finestra con su scritto l'esito dell'autenticazione positiva. Ora che abbiamo spiegato cosa vogliamo realizzare iniziamo vedendo i due strumenti principali che andremo ad utilizzare. 2. Tools La maggior parte del lavoro consiste nel disegnare la parte grafica. Per velocizzare questo processo esistono programmi per lo sviluppo rapido delle interfacce grafiche i cosiddetti RAD “Rapid Application Development”. Questi programmi permettono di disegnare l'interfaccia grafica andando a costruire la struttura gerarchica che tiene assieme i vari oggetti grafici; oltre a questo permettono anche di impostare proprietà e comportamento dei vari componenti grafici. Per questa guida utilizzeremo Glade un programma RAD che ci permetterà di disegnare la nostra interfaccia grafica. Con questo programma andremo a strutturare le nostre due interfacce di dialogo componendo i vari oggetti grafici. Il programma crea un file XML che contiene la struttura statica dell'interfaccia, elencando le componenti e le proprietà definite con Glade. Andiamo a vedere Glade come si presenta graficamente.
  • 4. Ispettore Proprietà Tavolozza Notiamo varie parti in questo programma: una Tavolozza a sinistra, con le componenti che possiamo trascinare all'interno della nostra GUI; un Ispettore in alto a destra, con la struttura gerarchica degli oggetti della nostra GUI, per il momento osserviamo che tra i widget vi è solo la finestra “window” che andremo a creare nei passi successivi; un pannello Proprietà in basso a destra, sotto l'ispettore, con le proprietà degli oggetti che selezioniamo, attraverso il quale andremo a modificare dimensioni e caratteristiche delle componenti della nostra GUI. L'altro programma utilizzato in questa guida è Anjuta DevStudio un IDE “Integrated Development Environment” per applicazioni C/C++ e GNOME/Gtk+. Questo programma ci permette di creare e gestire l'intero progetto oltre a darci la possibilità di modificare l'interfaccia grafica direttamente dal Designer integrato. 3. Concetti teorici Prima di continuare bisogna introdurre un po' di concetti teorici; verranno solo introdotti gli oggetti (grafici e non) che utilizzeremo ed è consigliato rileggere questa parte dopo aver completato la
  • 5. guida. Per la nostra GUI utilizzeremo l'oggetto grafico GtkWindow che ci permette di racchiudere al suo interno altri oggetti. I vari oggetti appartengono alla libreria Gtk e sono organizzati in una struttura gerarchica (potete cercare rapidamente e navigare all'interno della libreria tramite il programma DevHelp “A developers' help browser for GNOME”). In particolare distinguiamo diverse tipologie di oggetti: Containers oggetti contenitori che servono per contenere e dare struttura alle varie componenti; utilizzeremo per tale scopo tre differenti oggetti grafici contenitori, GtkVBox, GtkHBox, GtkHButtonBox. GtkVBox e GtkHBox servono per separare e contenere verticalmente e orizzontalmente i vari oggetti, mentre GtkHButtonBox serve per contenere e separare orizzontalmente vari bottoni (per creare una pulsantiera). Controllo e Visualizzazione oggetti utili per l'iterazione con l'utente. Tra questi utilizzeremo GtkLabel, GtkEntry, GtkButton. Oltre agli oggetti citati andremo ad utilizzare un oggetto non grafico GtkBuilder. Questo oggetto ci permette di descrivere un'interfaccia grafica tramite un file XML che definisce la User Interface. In altre parole a partire dal file XML, creato e modificato con Glade, è possibile creare un'interfaccia che ci consente di comunicare con l'oggetto grafico rappresentante la nostra GUI. Segnali e gestori (callback) GTK è un toolkit guidato dagli eventi. La nostra GUI rimane in attesa, intrappolata all'interno del ciclo gtk_main, che qualcosa accada. Quando si ha un evento, come la pressione di un bottone, verrà emesso il segnale appropriato dal componente grafico “widget” interessato. Per collegare questo segnale ad un'azione appropriata, dobbiamo predisporre un gestore che catturi il segnale o i segnali emessi e chiami la funzione corretta. Come vedremo questo viene fatto con l'istruzione: gint gtk_signal_connect ( Gtk_Object *object, gchar *name, GtkSignalFunc func, gpointer func_data ); L'istruzione riportata prende come primo argomento il widget che emetterà il segnale, come secondo il nome del segnale che si vuole catturare, come terzo la funzione che verrà invocata per gestire il segnale, e come ultimo argomento i dati che sono passati al gestore. Il valore di ritorno di tipo gint è un identificativo di questo gestore. Come si può immaginare ogni segnale può essere gestito anche con più di una funzione; le funzioni di gestione diverse verranno eseguite in sequenza. Tramite questo identificatore si ha la possibilità successivamente di rimuovere questo gestore, e lo si fa tramite il comando: void gtk_signal_disconnect ( Gtk_Object *object,    gint id ); Passando il widget da cui si vuole rimuovere il gestore di segnale e l'identificativo restituito da una delle funzioni signal_connect, si può rimuovere il gestore di segnale che si desidera dal widget. Questa gestione dei segnali può essere fatta in modo rapido direttamente in Glade nella scheda Signals del pannello Propietà. Come vedremo più avanti basta definire solo la funzione di gestione nel nostro codice, affinché il collegamento segnale/funzione viene fatto in automatico.
  • 6. 4. Creiamo la nostra GUI In questa parte alterneremo una sequenza di passi utilizzando i due programmi Anjuta e Glade al fine di realizzare la nostra interfaccia grafica. Anjuta: creiamo un nuovo progetto. Aprite il programma Anjuta, e create un nuovo progetto: • vi verrà richiesto che tipo di progetto volete creare, selezionate GTK+; • date un nome al progetto; • selezionate una destinazione per il progetto. Osserviamo che nella cartella di destinazione data, viene creato il progetto. Per poter lanciare quanto creato (cioè Execute dal menù run o semplicemente F3) bisogna prima configurare e generare il progetto. Generiamo il progetto: • dal menù Build premi Build Project (opp. Maiusc+F7): viene richiesto di configurare il progetto. Lasciate la voce Configuration selezionata su Debug ed andate avanti premendo Execute; (NOTA: se non viene data la possibilità di eseguire Build Project è perché bisogna configurare il progetto manualmente tramite la voce Configure Project... sotto il menu Build) • verranno visualizzati dei messaggi, ed alla fine se tutto è andato correttamente viene visualizzato “Completed successfully”. Notiamo che è stata creata la cartella Debug. Ora lanciamo per la prima volta quanto creato al passo precedente: • dal menù Run premi Execute (opp. F3); • apparirà una finestra di nome “window”, e osserviamo anche i messaggi nel Terminale dell'IDE; • per il momento non preoccupiamoci del warning “Gtk-WARNING” tra poco lo andiamo a correggere. Ora che abbiamo visto per la prima volta la nostra finestra, andiamo a vedere anche dove si trova nell'area del progetto. In Anjuta, nel riquadro Files, andate a vedere nella cartella src; al suo interno troviamo diversi file, ma non tutti ci interessano, solo alcuni di questi verranno da noi modificati. Cominciamo a creare la nostra finestra di richiesta dati; premi con il tasto destro sul file *.ui e seleziona apri con Disegnatore di interfacce grafiche. Consiglio di non utilizzare il disegnatore “integrato” con Anjuta, ma quello separato installato e visto in precedenza; lo distinguiamo perché quello separato si trova sotto la linea nel menù che appare. Se non lo trovate in questo menù è perché non vi è una associazione tra il file con estensione *.ui e il disegnatore di interfacce grafiche Glade. Quindi possiamo aprirlo direttamente noi andando tramite Nautilus nella cartella /src del progetto e premendo col tasto destro, apritelo con Glade. Se abbiamo seguito attentamente e ci troviamo con quanto detto sopra vediamo apparire Glade con la nostra finestra già caricata. La figura mostrata in precedenza visualizza quanto detto; il rettangolo al centro è la nostra finestra creata in automatico nei passi precedenti. Andiamo a modificarla. Glade: modifica della finestra di richiesta credenziali Per cominciare selezioniamo la finestra, possiamo farlo sia dall'ispettore che premendo sull'oggetto stesso. Nel pannello proprietà sotto la scheda General, andare a modificare i seguenti valori: • date un nome Name alla finestra, ad esempio “connectionWindow”;
  • 7. • impostare un titolo Window Title per la finestra, ad esempio “Autenticazione”; • impostare che la finestra non è ridimensionabile Resizable impostato su no; • impostare la Posizione nella quale la finestra deve apparire, mettere Centrato; • impostare una larghezza e altezza predefinita Default Width e Height: 350 x 220; Passate alla scheda Common ed impostare: • impostare una larghezza e altezza richiesta Request Width e Height: 350 x 220; Sotto la scheda Signals è possibile impostare i gestori per i segnali che vogliamo gestire; ad esempio cosa vogliamo fare quando la finestra viene chiusa. La creazione automatica da parte del programma ha già provveduto per noi ad impostare il gestore destroy() per gestire la chiusura della finestra; in pratica quando il segnale di distruzione della finestra destroy sotto la voce GtkObject viene emesso, viene intercettato dal gestore destroy() che troviamo dichiarato e definito nei file callbacks.*. Se ricordiamo bene, la prima volta che abbiamo lanciato il programma, abbiamo riscontrato un “Gtk-WARNING” per via dell'argomento NULL che di default viene passato al gestore; rimuovetelo in modo da non passare nulla al gestore del segnale. Se volete provate a salvare le modifiche fatte con Glade e rilanciare da Anjuta il programma (F3) e vedete che il warning è scomparso. Basta semplicemente fare Execute (F3) che il Build (src) (F7) viene eseguito in automatico. Noterete che al posto del warning Gtk­WARNING   **:   Could   not   lookup   object   NULL   on   signal   destroy   of   object  connectionWindow è comparso un altro messaggio Gtk­CRITICAL **: gtk_widget_show: assertion `GTK_IS_WIDGET (widget)' failed questo perché abbiamo modificato il nome del oggetto finestra da “window” a “connectionWindow” in Glade; quindi andiamo a modificare nel main (per il momento solo questo) la linea window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); in window = GTK_WIDGET (gtk_builder_get_object (builder, "connectioWindow")); Salvando e rilanciando (F3) il tutto notiamo che non ci sono più messaggi. Inoltre notate le modifiche apportate e cioè la finestra posizionata centralmente, il nome, la dimensione e la non ridimensionabilità della stessa. Andiamo ad inserire altri componenti all'interno della finestra. • per prima cosa dobbiamo dividere lo spazio in parti orizzontali ne bastano 4; per fare ciò prendere l'oggetto Vertical Box (GtkVBox) nella parte “Containers” e metterlo all'interno della finestra, selezionare il numero di elementi desiderati Number of items su 4; • inserite nei due spazi centrali, due spazi verticali, andando quindi a trascinarvi una Horizontal Box (GtkHBox) e selezionando 2 elementi. Il risultato dovrebbe essere questo.
  • 8. Notate la selezione fatta e nell'ispettore sul GtkVBox e come è impostata la proprietà Homogeneous. Questa rende gli spazi uguali tra loro, e la impostiamo solo sugli spazi orizzontali e non su quelli verticali, perché andremo a modificare dinamicamente il contenuto del primo spazio orizzontale, da una Label con una sola riga di testo ad una con due righe. Inseriamo altri elementi. • prendere una Label (GtkLabel) nella parte “Control and Display” e posizionarla all'interno del primo spazio orizzontale; • modificate nome ed etichetta alla label, mettendo Name “connectionMessage” e Label “Inserisci le credenziali d'accesso”; • sempre sulla label impostare Format label - justification a Center; • prendere una Horizontal Button Box (GtkHButtonBox) nella parte “Containers” e posizionarla all'interno dell'ultimo spazio orizzontale, e selezionare un numero di elementi pari a 1; • prendere un Button (GtkButton) nella parte “Control and Display” e posizionatelo all'interno dell'unico “spazio bottone” della pulsantiera appena creata. • modificate nome ed etichetta del bottone, mettendo Name “connectionButton” e Label “Connetti”. Andiamo ora ad inserire la parte relativa alla Username ed alla Password. • Inserire due Label negli spazi verticali di sinistra e due Text Entry (GtkEntry) negli spazi di destra; • modificare la Label delle due Label: quella in alto “Username” e quella in basso “Password”; • modificate alcune proprietà delle TextEntry appena inserite, in particolare date nome “usernameEntry” e “passwordEntry” ed una Maxmum length pari a 30;
  • 9. impostare nella TextEntry passwordEntry la Visibility su NO, questo per mascherare l'input con il carattere inserito in Invisible character; Se provate a lanciare il programma noterete una leggera differenza tra le lunghezze delle TextEntry/Label corrispondenti; questo è dovuto alla lunghezza delle Label che cambia in base al proprio contenuto. Andiamo a migliorare questo aspetto estetico: • impostare la Width request sotto la scheda Common richiesta delle Label username e password a 100; • sotto la scheda Packing impostare Expand su NO. Ora se visualizziamo di nuovo la nostra finestra notiamo che il tutto compare più allineato ed omogeneo. Prima di modificare anche i segnali impostati direttamente da Glade, andiamo a vedere un po' il codice e a fare qualche modifica per collegare qualche segnale emesso dagli oggetti grafici. Anjuta: cominciamo a modificare il codice Quello che segue è il codice del main.c così come generato alla creazione del progetto, eccetto che per la modifica fatta al nome della finestra “connectionWindow”. #include <gtk/gtk.h> #include "callbacks.h"  #define UI_FILE "src/tuorialgtk.ui"    GtkWidget*  create_window (void)  {  GtkWidget *window;  GtkBuilder *builder;  GError* error = NULL;  builder = gtk_builder_new ();  if (!gtk_builder_add_from_file (builder, UI_FILE, &error))  {  g_warning ("Couldn't load builder file: %s", error­>message);  g_error_free (error);  }  /* This is important */  gtk_builder_connect_signals (builder, NULL);  window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow")); 
  • 10.   g_object_unref (builder);    return window;  }  int  main (int argc, char *argv[])  {    GtkWidget *window;  #ifdef ENABLE_NLS  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF­8");  textdomain (GETTEXT_PACKAGE);  #endif  gtk_set_locale ();  gtk_init (&argc, &argv);  window = create_window ();  gtk_widget_show (window);  gtk_main ();  return 0;  } Cercherò di commentare tutte le parti importanti di questo pezzo di codice. Per cominciare si include la libreria Gtk. #include <gtk/gtk.h> All'interno del main la prima cosa che si fa è l'inizializzazione della libreria per poter utilizzare le componenti grafiche Gtk. gtk_init(&argc, &argv); Viene resa visibile la finestra creata. gtk_widget_show(window); Ed infine si entra nel ciclo principale con la funzione: gtk_main (); Da questo ciclo si esce quando viene chiamata la funzione gtk_main_quit() che viene chiamata automaticamente con la chiusura della finestra (lo vediamo più avanti). Vediamo ora la funzione create_window(). Osserviamo che in questa funzione facciamo uso della nostra finestra disegnata con Glade, UI_FILE definito sopra #define UI_FILE "src/tuorialgtk.ui". In particolare la utilizziamo utilizzando un oggetto di tipo GtkBuilder che da definizione è proprio una interfaccia per file testuali come XML. GtkBuilder è un oggetto ausiliario che legge descrizioni testuali di una interfaccia utente e istanzia l'oggetto descritto. I passi principali per riferirci ed utilizzare una interfaccia grafica descritta tramite un file XML sono i seguenti:
  • 11. 1 ­ builder = gtk_builder_new () 2 ­ gtk_builder_add_from_file (builder, UI_FILE, &error))  3 ­ gtk_builder_connect_signals (builder, NULL) 4 ­ window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow")) 5 ­ g_object_unref (builder) Per prima cosa si crea un GtkBuilder con il comando gtk_builder_new(); possiamo passare una descrizione al GtkBuilder, tramite la funzione gtk_builder_add_from_file(). Un altro passo importante è il collegamento con i segnali. Se nella parte grafica abbiamo dichiarato dei gestori di risposta a segnali emessi dagli oggetti grafici, come ad esempio il nostro destroy(), per collegarli alle nostre funzioni di gestione scritte nei file callbacks.* dobbiamo chiamare un metodo gtk_builder_connect_signal() che quindi mette in corrispondenza i gestori della descrizione con i relativi gestori. builder = gtk_builder_new ();  if (!gtk_builder_add_from_file (builder, UI_FILE, &error))  {  ... }  /* This is important */  gtk_builder_connect_signals (builder, NULL); Per comprendere meglio l'importanza di questo comando gtk_builder_connect_signal()  provate a commentarlo e a lanciare il programma. Noterete che la finestra viene distrutta ma il programma rimane nel ciclo gtk_main() questo avviene perché non vi è un'associazione tra il segnale emesso dalla finestra quando viene distrutta e la chiamata al nostro gestore destroy() e quindi alla chiamata gtk_main_quit(). 1° viene premuto il bottone per chiudere la finestra. 2° l'oggetto grafico connectionWindow ha dichiarato in Glade che vuole gestire il segnale destroy di GtkObject con il gestore destroy. 3° viene cercato quindi un gestore destroy nel codice, questo grazie al comando gtk_builder_connect_signals(). 4° viene quindi eseguito il comando gtk_main_quit () che oltre a chiudere la finestra tramite il gestore delle finestre esce anche dal ciclo gtk_main (). void  destroy (GtkWidget *widget, gpointer data)  {  gtk_main_quit ();  } Quella sopra riportata è la sequenza di passi eseguita se il comando gtk_builder_connect_signals() sarebbe decommentato. Quindi al momento di cercare il gestore destroy() come dichiarato sul file XML *.ui tramite Glade lo si trova correttamente nel codice eseguito. Mentre se il comando fosse commentato non vi sarebbe un collegamento tra i gestori dei segnali dichiarati in Glade e le funzioni presenti nel programma e quindi non verrebbe eseguito il comando gtk_main_quit(). Dopo aver fatto questa prova rimuovete il commento. Per rendere il programma più leggibile, rinominate il gestore destroy() in my_destroy() sia nei
  • 12. file callbacks.* e sia in Glade (sotto la linguetta Signals nelle Proprietà dell'oggetto connectionWindow in corrispondenza del segnale GtkObject – destroy nella colonna Handler). Con la seguente chiamata è possibile prendere un puntatore ad un oggetto dell'interfaccia grafica disegnata. window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow")); In questo caso prendiamo un riferimento alla nostra finestra “connectionWindow”. Ultimo importante passo è il comando: g_object_unref (builder); Con quest'ultimo ci assicuriamo che quando le referenze a questo oggetto sono diventate nulle, l'oggetto viene rilasciato, cioè la memoria occupata viene liberata. Ora proviamo a collegare il nostro gestore rinominato in my_destroy() con il segnale emesso dal pulsante quando viene premuto. Per fare questo basta andare ad aggiungere nella funzione create_window() le seguenti istruzioni. { ... GtkWidget *connectionButton;  ...   connectionButton = GTK_WIDGET (gtk_builder_get_object (builder,"connectionButton"));  gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked",                      GTK_SIGNAL_FUNC (my_destroy), NULL);  ... } Prendiamo un riferimento al bottone e colleghiamo tramite la funzione gtk_signal_connect(), il segnale emesso dal bottone quando viene premuto, al nostro gestore. Notate il cast a GTK_OBJECT  (connectionButton), il segnale “clicked” emesso dal precedente oggetto, e il nome del gestore con il relativo cast GTK_SIGNAL_FUNC (my_destroy). In questo modo la nostra finestra si chiuderà quando viene premuto il tasto “Connetti”. Salvate e lanciate il tutto e osservate se funziona. In questo esempio abbiamo visto come collegare dinamicamente con gtk_signal_connect()  un segnale al suo gestore. Nota che era possibile farlo anche da Glade andando a dichiarare my_destroy() come gestore per l'evento clicked di GtkButton, come mostrato in figura, ed omettendo quanto sopra. Ora andiamo a collegare l'evento “bottone premuto” ad un gestore che ci stampa nel terminale le credenziali inserite; questo per mostrare la creazione di un nuovo gestore e come reperire i dati inseriti. Per prima cosa dobbiamo aggiungere la dichiarazione e definizione di un gestore che chiameremo check_data().
  • 13. // nel file callback.h void check_data (GtkWidget *widget, gpointer data); // nel file callbacks.c void check_data (GtkWidget *widget, gpointer data)  { printf(“FACCIO QUALCOSA!! n”); } Una volta inserito il nostro nuovo gestore lo colleghiamo al segnale “clicked” del nostro bottone. // nel file main.c gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked",                      GTK_SIGNAL_FUNC (check_data), NULL); Ora quando premiamo il bottone osserviamo la stampa nel Terminale. Per prendere il contenuto inserito nelle GtkEntry dobbiamo prendere dei riferimenti agli oggetti “usernameEntry” e “passwordEntry”. Per fare ciò abbiamo bisogno del nostro oggetto GtkBuilder. Possiamo procedere in diversi modi. Possiamo dichiarare il puntatore GtkBuider invece che nel metodo create_window nel nostro main() o come variabile globale; dobbiamo inoltre stare attenti all'istruzione g_object_unref(builder)  che renderebbe inutilizzabile la variabile. Ecco cosa faremo: • dichiariamo la variabile GtkBuilder *builder nel main; • spostiamo l'istruzione g_object_unref (builder)  all'uscita dal gtk_main() quindi alla fine del nostro main(); • spostiamo l'istruzione builder = gtk_builder_new()  nel main prima della chiamata a create_window(); • passiamo il puntatore builder al metodo create_window (GtkBuilder *builder) {}; All'interno del gestore check_data() abbiamo bisogno del riferimento al nostro builder, per collegarci alla descrizione XML fatta con Glade e quindi prendere i riferimenti ai dati inseriti. Per fare ciò è possibile passare questo riferimento al nostro gestore al momento della connessione del segnale con esso. Più precisamente quando utilizziamo gtk_signal_connect() nella funzione create_window(). gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked",                      GTK_SIGNAL_FUNC (check_data), builder); Il nostro gestore sarà quindi in grado di referenziale tramite l'oggetto GtkBuilder le nostre due GtkEntry e prenderne il contenuto. void  check_data (GtkWidget *widget, gpointer data)  {  GtkWidget *username = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                                         "usernameEntry"));  GtkWidget *password = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                                         "passwordEntry"));    gchar *usernameInput = gtk_entry_get_text(GTK_ENTRY(username));  gchar *passwordInput = gtk_entry_get_text(GTK_ENTRY(password));   
  • 14. printf("Username: %s Password: %s n", usernameInput, passwordInput);  } Nelle prime due istruzione vado a prendere i puntatori agli oggetti GtkEntry e nelle seguenti due ne vado a prendere il contenuto testuale. Notate il cast fatto sulla variabile “data” da gpointer a GTK_BUILDER (NB: funziona anche senza cast). Andremo ora a simulare l'autenticazione su un file di testo contente le credenziali di accesso. Create un file “account.txt” e posizionatelo nella stessa directory del progetto *.anjuta. Scrivete nel file alcune credenziali nella forma: username1 password1 username2 password2 ... ... FILE *fp; if ((fp = fopen("account.txt", "r")) == NULL) {  printf("ERRORE fopen R");  exit(1);  }  char user[30];  char pass[30];  int trovato = 0;   while (fscanf(fp,"%s %s", user, pass) != EOF ) {  if ( (strcmp(user,usernameInput) == 0) && (strcmp(pass,passwordInput) == 0) ) {  printf(“AUTENTICATO n”); trovato = 1;   } }  fclose(fp); if (trovato == 0) { printf(“NON AUTENTICATO n”); } Nel pezzo di codice riportato sopra si mostra la semplice gestione di un File testuale dalla sua lettura al confronto con il testo Username e Password inseriti sopra. La variabile “trovato” ci permette di uscire appena viene trovata una corrispondenza all'interno del file. Possiamo inserire questo codice all'interno del gestore check_data() subito dopo le due istruzioni gtk_entry_get_text(). Modifichiamo il codice per gestire il risultato dell'autenticazione nella GUI. Se i dati inseriti non sono “corretti” modifichiamo la label “Inserisci le credenziali d'accesso” in “ATTENZIONE!!nInserire i dati correttamente”, cancellando il testo inserito nelle due Entry. Di seguito le istruzioni da inserire al posto della stampa “NON AUTENTICATO”. GtkLabel *connectionMessage = GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),                                         "connectionMessage"));  gtk_label_set_text(connectionMessage,"Attenzione!!nInserire i dati correttamente");
  • 15. gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),                               "usernameEntry")),"");  gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),                               "passwordEntry")),""); Per prima cosa, prendiamo il riferimento alla Label contenente il messaggio di intestazione della finestra, cioè “connectionMessage”, e poi ne modifichiamo il testo utilizzando la funzione gtk_label_set_text() e cancelliamo l'eventuale testo inserito con gtk_entry_set_text(). A questo punto possiamo vedere lanciando il programma, che se i dati sono errati viene mostrata una label con un testo differente e vengono cancellati i dati inseriti. Mentre se i dati sono corretti viene stampato su terminale “AUTENTICATO” e viene ripresentata la finestra da capo. Noi a questo punto vogliamo mostrare il risultato “AUTENTICATO” su un'altra finestra per comunicarlo all'utente. Per cominciare andiamo a creare la nuova finestra, disegnandola con Glade. Glade: creiamo la finestra risultato Andando a modificare il nostro file *.ui, aggiungiamo una finestra. Basta premere sull'oggetto Window nella Tavolozza, tra i Toplevels. Poi: • date alla finestra le stesse proprietà della precedente: altezza e larghezza, posizione, ridimensionabilità; • dategli un nome “resultWindow” ed un titolo “Risultato”; • dichiarate il gestore “my_destroy” per la distruzione della finestra; • inserite all'interno della finestra una Label con nome “resultMessage” (l'etichetta non importa andiamo a modificarla prima di visualizzare la finestra); • sempre sulla label impostare Format label - justification a Center; Salvate il file con Glade e passiamo a modificare di nuovo il codice. Anjuta: collegare la finestra risultato Se l'autenticazione ha un esito positivo allora facciamo le seguenti cose: • settiamo la label della finestra di risultato dopo aver recuperato un riferimento ad essa; • visualizziamo la finestra risultato e nascondiamo quella di connessione. Quindi al posto dell'istruzione printf(“AUTENTICATO n”) inseriamo le seguenti istruzioni. GtkWidget *resultWindow; resultWindow = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data), "resultWindow"));  gtk_label_set_text(GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),
  • 16.                              "resultMessage")),"Autenticazione OK");  gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                              "connectionWindow")));   gtk_widget_show (resultWindow); A questo punto abbiamo analizzato tutto il codice utile al nostro scopo. Di seguito si riporta integralmente le parti significative del codice dei vari file. Main.c #include "callbacks.h" #define UI_FILE "src/tuorialgtk.ui"    GtkWidget*  create_window (GtkBuilder *builder)  {  GtkWidget *window;  GtkWidget *connectionButton;  GError* error = NULL;  if (!gtk_builder_add_from_file (builder, UI_FILE, &error))  {  g_warning ("Couldn't load builder file: %s", error­>message);  g_error_free (error);  }  /* This is important */  gtk_builder_connect_signals (builder, NULL);  window = GTK_WIDGET (gtk_builder_get_object (builder, "connectionWindow"));    connectionButton = GTK_WIDGET (gtk_builder_get_object (builder,                                   "connectionButton"));  gtk_signal_connect (GTK_OBJECT (connectionButton), "clicked",                             GTK_SIGNAL_FUNC (check_data), builder);    return window;  }  int  main (int argc, char *argv[])  {    GtkWidget *window;  GtkBuilder *builder;  #ifdef ENABLE_NLS  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF­8");  textdomain (GETTEXT_PACKAGE);  #endif  gtk_set_locale ();  gtk_init (&argc, &argv);  builder = gtk_builder_new ();    window = create_window (builder);  gtk_widget_show (window);  gtk_main ();    g_object_unref (builder);  return 0;  }
  • 17. Callbacks.h #include <gtk/gtk.h>  void my_destroy (GtkWidget *widget, gpointer data);  void check_data (GtkWidget *widget, gpointer data); Callbacks.c #include "callbacks.h"  #include <stdio.h>  #include <stdlib.h>  #include <string.h>  void  my_destroy (GtkWidget *widget, gpointer data)  {  gtk_main_quit ();  }  void  check_data (GtkWidget *widget, gpointer data)  {  GtkWidget *resultWindow;  GtkWidget *username = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                                         "usernameEntry"));  GtkWidget *password = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                                         "passwordEntry"));    gchar *usernameInput = gtk_entry_get_text(GTK_ENTRY(username));  gchar *passwordInput = gtk_entry_get_text(GTK_ENTRY(password));  FILE *fp;    if ((fp = fopen("account.txt", "r")) == NULL) {  printf("ERRORE fopen R");  exit(1);  }  char user[30];  char pass[30];  int trovato = 0;    while ( fscanf(fp,"%s %s", user, pass) != EOF) {     if ( (strcmp(user,usernameInput) == 0) &&                    (strcmp(pass,passwordInput) == 0) ) {  resultWindow = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                        "resultWindow"));  gtk_label_set_text(GTK_LABEL(gtk_builder_get_object (GTK_BUILDER(data),                               "resultMessage")),"Autenticazione OK");    gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER(data),                               "connectionWindow")));   gtk_widget_show (resultWindow);  trovato = 1;     }  }  fclose(fp);  if (trovato == 0) { 
  • 18. GtkLabel *connectionMessage = GTK_LABEL(gtk_builder_get_object                                            (GTK_BUILDER(data), "connectionMessage"));  gtk_label_set_text(connectionMessage,"Attenzione!!nInserire i dati                                                                        correttamente");  gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),                                            "usernameEntry")),"");  gtk_entry_set_text (GTK_ENTRY(gtk_builder_get_object (GTK_BUILDER(data),                                            "passwordEntry")),"");    }  } Risorse Importanti risorse dove trovare altra documentazione sono: • http://www.micahcarrick.com/gtk-programming/ • http://library.gnome.org/devel/gtk-tutorial/stable/ • http://tadeboro.blogspot.com/2009/09/glade3-tutorial-1-introduction.html • http://www.hds619.net/blog/guida-gtk-a-puntate/ • http://anjuta.org/ • http://glade.gnome.org/