====== Discussione introduttiva sullo sviluppo di programmi multipiattaforma dotati di interfacce grafiche ====== Autore: **//Fabio Di Matteo//** - **//Santo Patti//** \\ Ultima revisione: **//08/09/2008//** \\ \\ ===== Ingredienti ===== * Glade (disegnatore di interfacce) * Libglade (libreria che perette di usare i file generati da glade con il C) * Editor di testo per sviluppatori (Vi, Emacs,Nano,Scite, Gedit etc..) * Compilatore Gcc * Pkg-config (programma che serve per passare i giusti parametri a gcc in modo dinamico) * GNU Make * opzionalmente GDB (debugger) E' da notare come nel mondo Unix si preferiscono usare programmi molto specializzati in un singolo compito piuttosto che usare un programma tuttofare come lo sono per esempio gli ide come Visual Basic, Delphi, Visual C++ etc... . Esistono comunque alcuni IDE degni di nota come il progetto [[http://www.lazarus.freepascal.org/|Lazarus]] che altro non è che un clone di Delphi che però fa uso del potentissimo FreePascal. ===== Introduzione ===== Si tratterà lo sviluppo di applicazioni dotate di interfaccia grafica su piattaforma GNU/Linux e non solo; una applicazione dotata di interfaccia grafica oggigiorno deve: * Usare un linguaggio portabile o Standard ISO o ANSI (Es. C/C++) o Linguaggio interpretato (Es. Python, Perl, Ruby etc...) , noi tratteremo il primo caso. * Sviluppare codice modulare o Separazione contesti: (Es. librerie funzionali separate dal codice per l'interfaccia grafica). * Usare strumenti di sviluppo liberi in modo tale da avere sempre pieno controllo del vostro codice. * Interfaccia grafica adattabile, ovvero usare template per la GUI (Es. libglade + XML) - in questo modo tutta la grafica dell'interfaccia viene descritta in un file di testo (XML) , questo file viene poi caricato nel nostro programma grazie ad una libreria di nome Libglade . In seguito libglade "dice" alle GTK+ come disegnare l'interfaccia. * Usare librerie grafiche portabil (Es. GTK+, FLTK) - esula dal nostro tutorial. \\ **Approfondimenti:** \\ C e altri lunguaggi --> http://www.freemedialab.altervista.org/wiki/doku.php?id=libri:programmazione \\ GTK+ --> http://www.mathematik.uni-ulm.de/help/gtk+-1.1.3/gtk_tut_it.html#toc2 ===== Come realizzare questo file di testo XML ? ===== Esiste un pratico programmino che permette di disegnare (letteralmente) con il mouse la nostra interfaccia grafica, si chiama Glade 3.x. Non appena avviato Glade assomiglia parecchio ad un classico programma di disegno, infatti possiede una tavolozza, dove al posto degli strumenti artistici, sono collocati i classici oggetti che formano le interfacce grafiche di oggi, come finestre, conteintori, pulsanti, caselle di testo etc... **In questa guida creeremo soltanto una finestra con dentro un pulsante e una casella di testo. ** ===== OK, creiamo la nostra interfaccia con Glade ! ===== Disegnamo l'interfaccia: - Avviamo Glade; - Clicchiamo sul pulsante "Finestra" nella tavolozza; - Clicchiamo sul pulsante "Fisso" nella tavolozza, e poi clicchiamo sulla nostra finestra; - Clicchiamo sul pulsante "Pulsante" nella tavolozza, e poi clicchiamo sulla nostra finestra; - Muoviamo e ridimenzioniamo il pulsante tenendo premuto "shift" o "Maiusc" sulla tastiera; - Clicchiamo sul pulsante "Entrata a testo" nella tavolozza, e poi clicchiamo sulla nostra finestra; Associamo al click del pulsante le istruzioni di una funzione (detta in gergo Callback) che scriveremo fra poco: - Clicchiamo sul pulsante; - Clicchiamo sulla scheda "Segnali" presente nella colonna dell'ispettore; - Selezioniamo il segnale "Clicked", e come gestore "on_button1_clicked" (che è il futuro nome della funzione che verrà chiamata ogni qualvolta pigeremo il pulsante); - Salviamo il nostro file di testo XML come ''interfaccia.glade'' nella directory del nostro progetto . ===== Andiamo al codice ===== * Aprite il vostro editor di testo preferito e scrivete questo testo: #include //includo le librerie gtk e glade. #include GladeXML *xml; //questo è il puntatore al file xml che contiene l'interfaccia GtkWidget *widget; //questa variabile serve per recuperare di volta in volta il //widget (ovvero l'oggetto ) che vogliamo usare void on_button1_clicked (GtkWidget *widget, gpointer user_data) //questa è una callback ovvero una funzione associata ad un evento { // per esempio la pressione di un pulsante widget = glade_xml_get_widget (xml, "entry1"); //scrivo qualcosa nella entry gtk_entry_set_text (widget, "Ciao"); } void on_window1_delete_event(GtkWidget *widget, gpointer user_data) //altra callback associata alla chiusura della { // finestra "window1" gtk_main_quit(); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); /* Carica l'interfaccia dal file di glade */ xml = glade_xml_new ("interfaccia.glade", NULL, NULL); /* connette tutti gli eventi dei widget alle rispettive funzioni */ glade_xml_signal_autoconnect(xml); /* Avvia il ciclo principale delle gtk*/ gtk_main (); return 0; } salviamo il testo nel file ''main.c'' . ===== Compiliamo il progetto ===== Per compilare il nostro programma, ovvero renderlo eseguibile alla macchina digitare da un terminale : gcc -o main main.c `pkg-config –cflags –libs libglade-2.0` -export-dynamic I flags (ovvero i parametri del compilatore) per compilare il file vengono generati “al volo” dal programma pkg-config grazie al comando `pkg-config –cflags –libs libglade-2.0`, invece l’opzione -export-dynamic serve ad autoconnetere i vari componenti dell’interfaccia (bottoni, etichette etc...) alla relativa callbacks che porta quasi lo stesso nome es: on_[nome widget]_[tipo di evento] (GtkWidget *widget, gpointer user_data) . ===== Automatizzare la compilazione con Make ===== Può essere noioso, ogni volta che dobbiamo compilare il nostro progetto, digitare tutta questa stringa quindi ci viene in aiuto una pratica utility di nome GNU Make o più semplicemente Make. Infatti scrivendo un semplicissimo script di nome ''Makefile'' potremmo ogni volta compilare il nostro programmino semplicemente scrivendo ''make'' dal terminale , oppure farlo compilare al nostro editor di testi preferito che avrà sicuramente una funzione che permette di usare make cliccando su di un bottone o qualcosa del genere. \\ Di seguito un semplice Makefile che in pratica è sempre lo stesso se si vogliono fare programmi che usano soltanto libglade e le altre librerie standard del compilatore: CPP = gcc OPTS = `pkg-config --cflags --libs libglade-2.0` -export-dynamic all: $(CPP) main.c -o main $(OPTS) clean: rm main Salviamo questo testo in un file di nome Makefile e inseriamolo nella stessa directory del codice, dopodicchè basterà lanciare il comando ''make'' ed il nostro programmino sarà compilato. ===== Trovare gli errori con il Debugger ===== E se il nostro programmino è cresciuto ed abbiamo bisogno di un debugger per scovare gli errori?\\ Usiamo un programma di nome GDB (Gnu Source-Level Debugger). Ecco le operazioni di base che possiamo svolgere con il GDB: * Interrompere il nostro programmino se si verificano certe condizioni; * Analizzare quello che é accaduto, quando il nostro programma é stato interrotto; * Cambiare il valore delle variabili del nostro programmino, in modo che possiamo vedere gli effetti delle nostre correzioni; Per abilitare il supporto a GDB basta passare al compilatore il parametro ''-g'' , quindi ecco il nostro Makefile : CPP = gcc OPTS = -g `pkg-config --cflags --libs libglade-2.0` -export-dynamic all: $(CPP) main.c -o main $(OPTS) clean: rm main Utilizzo in breve... Avviamo GDB con il nostro progetto: gdb -quiet Lanciamo il programma: (gdb) run Possiamo bloccare l'esecuzione del programma creando dei breackpoints: (gdb) break Questa direttiva imposta un breakpoint alla funzione specificata. Quale funzione dovrà appartenere al vostro programma. Quando il programma si bloccherà potrete interagire con tutte le variabili definite all'interno della funzione su cui è stato impostato il breakpoint. (gdb) break In questo modo impostiamo un breakpoint alla linea n dove n è il numero specificato come argomento dell'istruzione break. Tale numero si riferisce naturalmente alle linee del codice sorgente del vostro programma. (gdb) break <+offset> o <-offset> Questo comando si può utilizzare se già sono stati impostati altri breakpoint (almeno 1) e il programma ha interrotto la propria esecuzione su uno di questi. Il risultato è semplicemente quello di ottenere un nuovo breakpoint "offset" linee dopo quello su cui il programma si è bloccato, se offset è un numero positivo, prima altrimenti. (gdb) break nomefile:nomefunzione Viene impostato un breakpoint alla funzione specificata del file sorgente specificato. (gdb) break nomefile:numerolinea Viene impostato un breakpoint alla linea "numerolinea" del file sorgente specificato (gdb) break indirizzo-di-memoria Questo comando va utilizzato quasi esclusivamente se non avete a disposizione il file sorgente. Esso consente di impostare un breakpoint su di uno specifico indirizzo di memoria che potrete ottenere una volta disassemblato il file eseguibile. (gdb) break if Questa direttiva imposta un breakpoint alla linea "numerolinea" del file sorgente se e solo se si verifica la condizione specificata. (gdb) break Senza nessun argomento questo comando imposta un breakpoint sulla Successiva istruzione che deve essere eseguita. Una volta bloccata l'esecuzione... possiamo visualizzare il valore di una variabile con il comando: (gdb) print Approfondimenti: http://edu.os3.it/html/manual/impararec/node119.html **Buon sviluppo, hacker** :-D