Introduzione
Esistono molti modi per realizzare programmi dotati di interfaccia grafica usando le librerie grafiche GTK+ e la sua interfaccia PyGTK per Python.
In questa guida viene esaminato con un esempio l'utilizzo del costruttore di interfacce GtkBuilder integrato in PyGTK e in GTK+. GtkBuilder consente di realizzare un descrittore dell'interfaccia grafica in un file esterno XML che viene poi collegato al codice.
Prima vengono presentati un esempio di programmazione in Python utilizzando GTK+ senza file esterni e un altro esempio che usa il creatore di interfacce Glade e la sua libreria libglade.
Negli esempi viene realizzata un semplice applicazione grafica costituita da una finestra che contiene due pulsanti, il primo cambia il titolo della finestra, il secondo chiude l'applicazione.
Esempio senza costruttori
In questa prima versione del programma tutti gli oggetti grafici (widget) vengono creati dal codice richiamando le classi gtk.*. Il codice è una versione modificata dell'esempio helloword.py tratto dal tutorial presente nel sito ufficiale di PyGTK.
1 #!/usr/bin/env python
2 # esempio hello_gtk.py
3
4 import pygtk
5 pygtk.require('2.0')
6 import gtk
7
8 class HelloWorld:
9
10 def __init__(self):
11 self.mainWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
12
13 self.mainWindow.set_position(gtk.WIN_POS_CENTER_ALWAYS)
14 self.mainWindow.set_default_size(210, 60)
15 self.mainWindow.set_border_width(10)
16
17 self.hbuttonbox=gtk.HButtonBox()
18 self.mainWindow.add(self.hbuttonbox)
19
20 self.cmdOK = gtk.Button(label="_Ok", use_underline=True)
21 self.cmdOK.connect("clicked", self.on_ok, None)
22 self.hbuttonbox.add(self.cmdOK)
23 self.cmdOK.show()
24
25 self.cmdCancel = gtk.Button(label="_Cancel", use_underline=True)
26 self.cmdCancel.connect("clicked", self.on_quit, None)
27 self.hbuttonbox.add(self.cmdCancel)
28 self.cmdCancel.show()
29
30 self.hbuttonbox.show()
31 self.mainWindow.show()
32
33 def on_ok(self, *args):
34 print "on_ok occurred: Hello World"
35 self.mainWindow.set_title("Hello World")
36
37 def on_quit(self, *args):
38 print "on_quit occurred"
39 gtk.main_quit()
40
41 def main(self):
42 gtk.main()
43
44 if __name__ == "__main__":
45 hello = HelloWorld()
46 hello.main()
47
Per prima cosa è necessario importare PyGTK (almeno nella verione 2 per compaibilità) e le GTK+ stesse.
1 import pygtk
2 pygtk.require('2.0')
3 import gtk
4
Poi è necessario creare la classe HelloWorld...
1 class HelloWorld:
2 def __init__(self):
3
... e il suo costruttore.
La prima istruzione è la creazione della finestra principale. Si crea cioè una istanza della classe gtk.Window passando come parametro gtk.WINDOW_TOPLEVEL che indica una finestra principale. L'oggetto creato, mainWindow, viene poi messo a punto (posizione iniziale sullo schermo, dimensione iniziale, spessore bordi).
1 self.mainWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
2 self.mainWindow.set_position(gtk.WIN_POS_CENTER_ALWAYS)
3 self.mainWindow.set_default_size(210, 60)
4 self.mainWindow.set_border_width(10)
5
Quindi si aggiunge alla finestra un contenitore di pulsanti orizzontale, cioè una istanza della classe gtk.HButtonBox. Una finestra può contenere solo un widget ed è quindi necessario dotarla di un oggetto che sia in grado di contenere più controlli. Le button box, orizzontali o verticali, permettono ciò.
1 self.hbuttonbox=gtk.HButtonBox()
2 self.mainWindow.add(self.hbuttonbox)
3
All'interno del contenitore si inseriscono due pulsanti, istanze della classe gtk.Button.
1 self.cmdOK = gtk.Button(label="_Ok", use_underline=True)
2 self.cmdOK.connect("clicked", self.on_ok, None)
3 self.hbuttonbox.add(self.cmdOK)
4 self.cmdOK.show()
5
6 self.cmdCancel = gtk.Button(label="_Cancel", use_underline=True)
7 self.cmdCancel.connect("clicked", self.on_quit, None)
8 self.hbuttonbox.add(self.cmdCancel)
9 self.cmdCancel.show()
10
La prima istruzione del primo blocco crea l'oggetto cmdOK con la sua etichetta Ok. La seconda istruzione collega il segnale "clicked" tipico per i pulsanti, alla funzione on_ok, contenuta nella classe e dichiarata in seguito. La terza istruzione aggiunge il pulsante al contenitore hbuttonbox e l'ultima visualizza il pulsante. Il secondo blocco di istruzioni crea il pulsante cmdCancel e lo collega alla funzione on_quit, definita in seguito. Le ultime due istruzioni del costruttore della classe visualizzano il contenitore dei pulsanti e la finestra principale.
1 self.hbuttonbox.show()
2 self.mainWindow.show()
3
Il codice scritto sin qui permette solo di visualizzare la finestra con i due pulsanti. Perché l'applicazione faccia qualcosa è necessario creare le funzioni associate al segnale "clicked" dei due pulsanti, cioè all'azione dell'utente su di loro. Terminato il costruttore della classe si aggiungono le funzioni richieste.
1 def on_ok(self, *args):
2 print "on_ok occurred: Hello World"
3 self.mainWindow.set_title("Hello World")
4
La prima stampa al prompt di Python un avviso.
on_ok occurred: Hello World
Inoltre cambia il titolo della finestra scrivendoci "Hello Word".
1 def on_quit(self, *args):
2 print "on_quit occurred"
3 gtk.main_quit()
4
La seconda stampa al prompt un avviso e chiude l'applicazione con l'istruzione gtk.main_quit().
L'ultima funzione della classe è quella che attiva la finestra. L'istruzione gtk.main() deve essere presente in ogni applicazione GTK+.
1 def main(self):
2 gtk.main()
3
Terminata la classe, il modulo termina con la funzione che istanzia l'oggetto hello di classe HelloWorld() e lancia il metodo main() della classe appena descritto.
1 if __name__ == "__main__":
2 hello = HelloWorld()
3 hello.main()
4
Il file deve essere salvato, ad esempio con il nome hello_gtk.py, e deve essere reso eseguibile con l'istruzione chmod 755 /PERCORSO/hello_gtk.py.
Il risultato, lanciando l'applicazione, è una finestra di questo tipo:
Cliccando su Ok, il titolo della finestra cambia:
Al prompt compare il messaggio:
on_ok occurred: Hello World
Cliccando su Cancel, l'applicazione viene chiusa e al prompt compare:
on_quit occurred
Esempio con libglade
La seconda versione utilizza il costruttore di intefacce Glade. Per installarlo aprire un teminale e scrivere:
sudo apt_get install glade
Disegnare l'interfaccia
Avviare Glade da Applicazioni → Programmazione → Glade - Disegnatore di interfacce
Dal menù File di Glade scegliere Nuovo. Si aprirà la finestra Preferenze di.... Per utilizzare la libreria libglade è necessario scegliere l'opzione relativa e chiudere la finestra di dialogo. La stessa finestra può essere raggiunta, per file già salvati, da Modifica → Preferenze.
Dalla "tavolozza" (la colonna a sinistra), scegliere Finestra dalla sezione Livelli principali.
Nello spazio centrale comparirà una finestra vuota mentre nella colonna a destra, tra i Widget, comparirà la descrizione dell'oggetto window1. Nella sezione Proprietà Finestra sottostante rinominare la finestra in mainWindow assicurandosi che il tipo sia Livello principale.
A questo punto è necessario popolare la finestra di widget. Il primo da inserire è la button box orizzontale per contenere i pulsanti.
Tra i Contenitori scegliere Casella pulsanti orizzontale e poi cliccare nello spazio vuoto della finestra mainWindow. Nella finestra di dialogo che appare scrivere 2.
I pulsanti appariranno allineati verso i bordi della finestra, a differenza di quanto visto nel primo esempio. Per ottenere lo stesso risultato è necessario affinare i widget inseriti. |
Nella sezione Controllo e visualizzazione scegliere Pulsante e cliccare sulla finestra nel segnaposto vuoto a sinistra. Verrà creato un widget button.
Tra le proprietà dell'oggetto scegliere il tab Generale e rinominare il pulsante come cmdOK. Nello stesso tab, più in basso, selezionare Pulsante stock e nella tendina a comparsa scegliere gtk-ok. Nel tab Segnali, selezionare clicked nella colonna Sagnali, scegliendo on_cmdOK_clicked nella tendina a comparsa nella colonna Gestore. La riga deve risultare in grassetto.
Inserito il primo pulsante e precisato quale sarà il gestore (handler) dell'evento clicked, il pulsante OK è pronto per essere utilizzato nel codice Python.
Ripetere la procedura per il pulsante Cancel da inserire nella casella pulsanti orizzontale nel posto vuoto a destra. Il pulsante andrà rinominato come cmdCancel e gli si dovrà associare il gestore on_cmdCancel_clicked per l'evento clicked. Nel tab Generali scegliere Pulsante stock di tipo gtk-cancel.
Dopo aver ridimensionato a piacere la finestra, il risultato dovrebbe essere qualcosa del tipo:
La finestra Ispettore, in alto a destra, dovrebbe apparire così:
Salvare il file con il nome hello_glade.glade nella stessa cartella dove verrà salvato lo script Python. Il codice XML, visualizzato con un editor, è: {{{<?xml version="1.0" encoding="UTF-8"?> <glade-interface>
<!-- interface-requires gtk+ 2.16 --> <!-- interface-naming-policy project-wide --> <widget class="GtkWindow" id="mainWindow">
<child>
<widget class="GtkHButtonBox" id="hbuttonbox">
<property name="visible">True</property> <child>
<widget class="GtkButton" id="cmdOK">
<property name="label">gtk-ok</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="use_stock">True</property> <signal name="clicked" handler="on_cmdOK_clicked"/>
</widget> <packing>
<property name="expand">False</property> <property name="fill">False</property> <property name="position">0</property>
</packing>
</child> <child>
<widget class="GtkButton" id="cmdCancel">
<property name="label" translatable="yes">Cancel</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <signal name="clicked" handler="on_cmdCancel_clicked"/>
</widget> <packing>
<property name="expand">False</property> <property name="fill">False</property> <property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface> }}}
Codice per libglade
Il codice per il secondo esempio deve contenere un riferimento a libglade:
1 #!/usr/bin/env python
2 # esempio hello_glade.py
3
4 import pygtk
5 pygtk.require('2.0')
6 import gtk
7 import gtk.glade
8
9 class HelloWorld:
10
11 def __init__(self):
12
13 self.gladeMain = gtk.glade.XML("hello_glade.glade")
14
15 self.gladeMain.signal_connect("on_cmdCancel_clicked", self.on_quit)
16 self.gladeMain.signal_connect("on_cmdOK_clicked", self.on_ok)
17
18 self.mainWindow = self.gladeMain.get_widget("mainWindow")
19 self.mainWindow.set_position(gtk.WIN_POS_CENTER_ALWAYS)
20 self.mainWindow.set_default_size(210, 60)
21 self.mainWindow.show()
22
23 def on_quit(self, *args):
24 print "on_quit occurred"
25 gtk.main_quit()
26
27 def on_ok(self, *args):
28 print "on_ok occurred: Hello World"
29 self.mainWindow.set_title("Hello World")
30
31 def main(self):
32 gtk.main()
33
34 if __name__ == "__main__":
35 hello = HelloWorld()
36 hello.main()
37
Nelle dichiarazioni è necessario quindi importare, oltre a PyGTK e alle GTK+, anche libglade:
1 import pygtk
2 pygtk.require('2.0')
3 import gtk
4 import gtk.glade
5
Il costruttore della classe HalloWorld è leggermente diverso. La prima istruzione crea un oggetto gladeMain di classe XML di libbglade.
1 self.gladeMain = gtk.glade.XML("hello_glade.glade")
2
L'oggetto punta al file hello_glade.glade descrittore della finestra creato in precedenza con Glade.
Le due istruzioni successive collegano il codice con i segnali dichiarati in sede di costruzione dell'interfaccia:
1 self.gladeMain.signal_connect("on_cmdCancel_clicked", self.on_quit)
2 self.gladeMain.signal_connect("on_cmdOK_clicked", self.on_ok)
3
Come nel primo esempio sono collegati, tramite l' handler, alle due funzioni on_quit e on_ok.
L'oggetto mainWindow viene istanziato, diversamente dal primo esempio, con la funzione get_widget di gladeMain che punta alla finestra mainWindow del descrittore XML.
1 self.mainWindow = self.gladeMain.get_widget("mainWindow")
2
Le istruzioni successive fanno riferimento, come nel primo esempio, all'oggetto mainWindow. La dimensione iniziale della finestra, insieme a molte altre proprietà, può comunque essere modificata con Glade.
In questo caso non è necessario costruire i widget contenuti nella finestra. Sia il contenitore orizzontale che i due pulsanti sono stati costruiti con Glade e i loro eventisono già stati collegati nel codice. Restano solo da scrivere le due funzioni on_quit e on_ok e la funzione di ingresso main, identiche al primo esempio.
Salvato il programma come hello_glade.py e lanciato lo script, il risultato dovrebbe essere:
Cliccando sul pulsante OK il titolo della finestra cambia.
Esempio con GtkBuilder
GtkBuilder è un formato per la realizzazione di interfacce grafiche attraverso la descizione contenuta all'interno di file XML. Introdotto con la versione 2.12 delle librerie GTK+, ha un funzionamento simile a GladeXML della libreria libglade.
Oltre ad essere più potente consentendo di gestire un numero maggiore di widget,, il suo utilizzo consente di eliminare la dipendenza dei programmi GTK dalla libreria libglade, considerata deprecata dal progetto GNOME nella transizione verso la versione 3 dell'ambiente grafico.
Dalla versione 3.6.0 il RAD Glade permette di creare intefacce grafiche compatibili sia con libglade che con GtkBuilder (impostato di default).
Disegnare l'interfaccia
Avviare Glade da Applicazioni → Programmazione → Glade - Disegnatore di interfacce.
Dal menù File di Glade scegliere Nuovo. Si aprirà la finestra Preferenze di.... GtkBuilder è l'opzione di default. La stessa finestra può essere raggiunta, in ogni momento, da Modifica → Preferenze.
Alternativamente, si può modificare l'impostazione di un file creato per libglade modificando l'impostazione nella stessa finestra Preferenze di....
Salvare il file come hello_gtkBuilder.glade nella stessa cartella dove verrà salvato il codice. L'estensione del file è del tutto arbitraria e non ha nessuna influenza sull'esecuzione del programma. Il file XML assume con GtkBuilder questo aspetto:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="mainWindow">
<child>
<object class="GtkHButtonBox" id="hbuttonbox">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="cmdOK">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_cmdOK_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cmdCancel">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_cmdCancel_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>La differenza più evidente rispetto alla versione per libglade è l'utilizzo di classi object al posto delle classi widget.
Codice per GtkBuilder
Nello script Python per GtkBuilder non è necessario importare null'altro se non PyGTK e le librerie GTK+ stesse.
1 #!/usr/bin/env python
2 # esempio hello_gtkBuilder.py
3
4 import pygtk
5 pygtk.require('2.0')
6 import gtk
7
8 class HelloWorld:
9
10 def __init__(self):
11
12 self.gladeMain = gtk.Builder()
13 self.gladeMain.add_from_file("hello_gtkBuilder.glade")
14
15 self.gladeMain.connect_signals(self)
16
17 self.mainWindow = self.gladeMain.get_object("mainWindow")
18 self.mainWindow.set_position(gtk.WIN_POS_CENTER_ALWAYS)
19 self.mainWindow.set_default_size(210, 60)
20 self.mainWindow.show()
21
22 def on_cmdCancel_clicked(self, *args):
23 print "on_cmdCancel_clicked"
24 gtk.main_quit()
25
26 def on_cmdOK_clicked(self, *args):
27 print "on_cmdOK_clicked occurred: Hello World"
28 self.mainWindow.set_title("Hello World")
29
30 def main(self):
31 gtk.main()
32
33 if __name__ == "__main__":
34 hello = HelloWorld()
35 hello.main()
36
Il collegamento al file XML viene realizzato con due istruzioni nel costruttore della classe HelloWorld.
1 self.gladeMain = gtk.Builder()
2 self.gladeMain.add_from_file("hello_gtkBuilder.glade")
3
La prima crea una istanza del costruttore di classe gtk.Builder, la seconda collega il cotruttore con il file XML hello_gtkBuilder.glade appena creato con Glade.
L'struzione successiva intercetta tutti i segnali provenienti dal costruttore gladeMain e quindi dall'interfaccia hello_gtkBuilder.glade.
1 self.gladeMain.connect_signals(self)
2
Nel caso in cui in fase di realizzazione dell'interfaccia si fossero creati altri segnali non intercettati dal codice, il programma solleverebbe una avviso di runtime.
Nelle istruzioni successive viene creata la finestra mainWindow' mediante il metodo get_object della classe gtk.Builder`.
Con GtkBuilder gli eventi provenienti dall'interfaccia grafica vengono individuati mediante il nome dell' handler, in questo caso on_cmdCancel_clicked e on_cmdCancel_clicked, a cui devono corrispondere delle funzioni definite con lo stesso nome. Si tratta delle stesse funzioni già viste negli esempi precedenti, ma con il titolo obbligato (sia pur modificabile a picere nell'attribuire l' handler in ambiente Glade).
Se nel codice Python non fosse presente, ad esempio, la funzione on_cmdCancel_clicked e nel file XML fosse elencato un segnale il cui gestore ha lo stesso nome, in fase di runtime l'istruzione self.gladeMain.connect_signals(self) solleverebbe un avviso al prompt di Python:
/<PERCORSO>/hello_gtkBuilder.py:14: RuntimeWarning: missing handler 'on_cmdCancel_clicked'
Salvato il programma come hello_gtkBuilder.py e lanciato lo script, il risultato dovrebbe essere:
Cliccando sul pulsante OK il titolo della finestra cambia.
Note
Gli esempi della presente guida sono stati realizzati utilizzando Ubuntu 10.10 con GTK+ 2.22, PyGTK 2.21, Glade 3.7.0, libglade 2.12.
