Creare GUI con Python

Pubblicato il 5 Aprile 2005

Breve introduzione alle librerie disponibili

Python è un linguaggio molto potente e permette di ridurre di un terzo il codice scritto rispetto a Java. Nella creazione di interfacce grafiche di solito si scrive parecchio codice quindi Python ci permette di essere più produttivi. Per la scrittura di interfacce grafiche, Python ci mette a disposizione diverse strade. Ci sono infatti, diverse librerie utilizzabili e quasi tutte multipiattaforma.

Ogni sistema operativo ha la sua interfaccia grafica e ha i suoi widgets grafici. In generale ci sono degli oggetti che fanno oramai parte del concetto comune di widgets. Questi oggetti rappresentano ognuno una precisa tipologia di iterazione con il programma.

Ho elencato le librerie più utilizzate per scrivere applicazioni Python con interfaccia grafica:

  • TkInter - basate su le famose librerie TCL/TK.
  • wxPython - basate sulle librerie wxWidgets.
  • PyGTK - si appoggiano alle librerie GTK, utilizzate nel desktop Linux Gnome.
  • PyQT - si appoggiano alle librerie QT, utilizzate nel desktop Linux KDE.
  • PyObjC - wrapper per il framework Cocoa, utilizzato per scrivere applicazioni con interfaccia Aqua (quella di Mac OS X).
  • Win32All - Per scrivere applicazioni utilizzando le librerie grafiche di Windows.

La lista è molto più lunga, mi sono limitato a citare quelle maggiormente diffuse. Passiamo ora a descrivere quali sono le caratteristiche delle varie librerie e come scegliere la più adatta alle nostre esigenze.

Scelta della libreria

Se siete intenzionati a scrivere applicazioni ad interfaccia grafica che funzionino solo su sistemi Windows potete utilizzare Win32All. Avete il massimo supporto per qualsiasi oggetto grafico o funzionalità presente nei soli sistemi Windows.

Un altra libreria utilizzabile su un solo sistema operativo è la PyObjC. Si tratta di un wrapper per il linguaggio Objective-C e l'ambiente di sviluppo Cocoa. Quest'ultimo è stato introdotto con Mac OS X e permette di scrivere applicazioni con interfaccia Aqua.

Se invece dovete scrivere software in previsione di un utilizzo su sistemi operativi diversi la scelta cade soprattutto su wxPython ma anche su TkInter, PyQT e PyGTK. Tutte queste librerie sono multipiattaforma ma sono molto diverse fra di loro. Prima di tutto va detto che sono tutte e quattro dei wrapper verso librerie native scritte in C e compilate per i vari sistemi operativi. Non si tratta quindi di librerie scritte completamente in Python come sono le AWT e le Swing, scritte completamente in Java. Essendo scritte parzialmente in Python, ci sono vantaggi e svantaggi rispetto alle librerie pure come le Swing. Il vantaggio maggiore riguarda le prestazioni che sono di gran lunga superiori. Nel caso della libreria wxPython si ha un altro vantaggio: l'aspetto dell'interfaccia è identico a quello di applicazioni native. Con PyGTK e PyQT si possono realizzare applicazioni che presentano interfacce che si avvicinano alle applicazioni native. Comunque non avrete mai la compatibilità massima, infatti anche alcuni particolari oggetti grafici di wxPython si visualizzano in maniera diversa sui vari sistemi operativi.

La mia esperienza nello sviluppo di programmi ad interfaccia grafica si basa su alcune piccole applicazioni scritte con le PyGTK e diverse applicazioni realizzate con le wxPython. Ho una passione sfrenata per Linux e per il desktop Gnome, in passato ho scritto un semplice programma che mi permetteva di scaricare le foto dalla mia macchina fotografica Nikon Coolpix. Il tutto con Python 2.2 e PyGTK che avevo trovato nell'installazione base della Red Hat 8. Con TkInter ho scritto diverse applicazioni, tra cui anche un piccolo gestionale per apicoltori che faceva uso del database server MySQL. TkInter ha il pregio di essere velocissimo da utilizzare ma ha una serie di svantaggi che si porta dietro dall'utilizzo delle librerie TK. Lo svantaggio maggiore è la scarsa lista di componenti grafici disponibili e l'altro è l'aspetto dell'interfaccia che è simile ma non uguale a quella delle applicazioni native. Si tratta di una libreria che supporta tantissimi sistemi operativi ed è inclusa nella libreria standard di Python.

La migliore libreria in assoluto è sicuramente wxPython, è quella che permette buone performance, grafica ottima su tutti i sistemi operativi e un ampia collezione di oggetti grafici pronti all'uso. WxPython è diventata, già da un anno, la mia libreria preferita per le interfacce grafiche. L'ho utilizzata per diverse utility e per un piccolo software per le gestione di una gara ciclistica. In tutti i casi la libreria si è rivelata molto veloce e stabile, è di sicuro la migliore scelta che si possa fare attualmente.

TkInter

Si tratta di un wrapper delle librerie TK, permette di creare interfacce grafiche multipiattaforma ed è inclusa nella libreria standard di Python. È semplice da usare e molto potente. Gli oggetti grafici scarseggiano e per ovviare a questo problema si è data vita al progetto Pmw che mette a disposizione una serie di oggetti grafici avanzati. Essendo inclusa nella libreria standard, questa libreria, può essere utilizzata direttamente senza installare librerie esterne, che in alcuni casi, sono molto pesanti e quindi difficilmente distribuibili. Per creare una finestra con TkInter dobbiamo prima di tutto importare il modulo Tkinter. Creiamo la nostra classe Finestra e gli facciamo estendere la classe Tk. Nel costruttore aggiungiamo il costruttore delle super classe Tk.__init__(self) e poi aggiungiamo il titolo alla finestra. Registriamo l'evento di chiusura della finestra per far chiudere l'applicazione. Aggiungiamo il metodo mostra che chiameremo per visualizzare la finestra dopo averla inizializzata.

Listato 1 - esempio di interfaccia grafica TkInter:
from Tkinter import *

class Finestra(Tk):

	def __init__(self):
		"""Costruttore della classe Finestra
		"""
		Tk.__init__(self)
		self.title('Ciao da TkInter')
		self.geometry("%dx%d" % (220, 150))

		# creo il bottone
		b = Button(self, text='Ciao mondo !', command=self.helloWorld)
		b.place(x=15, y=15)
		
		# registro l'evento di chiusura della finestra		
		self.protocol('WM_DELETE_WINDOW', self.__chiudi)
		
	def mostra(self):
		"""Visualizza la finestra
		"""
		# mando in loop l'applicazione
		self.mainloop()
 
	def helloWorld(self):
		"""Stampa sullo standard output la stringa 'Hello world !'
		"""
		print 'Ciao mondo !'

	def __chiudi(self):
		"""Chiude l'applicazione alla chiusura della finestra
		"""
		self.destroy()
		
		
if __name__ == '__main__':
	f = Finestra()
	f.mostra()
screenshot su Mac OS X
Screenshot su Mac OS X
screenshot su Windows
Screenshot su Windows

WxPython

Si tratta di una libreria multipiattaforma che supporta moltissimi sistemi operativi. Mette a disposizione tantissimi oggetti grafici ed una struttura ad oggetti che facilità la vita allo sviluppatore. Per realizzare una finestra si utilizza la classe wx.Frame. La mia classe Finestra estende wx.Frame e permette quindi di avere tutte le caratteristiche di una finestra. Nel costruttore della mia classe chiamo il costruttore della super classe passando anche l'id, il titolo, le dimensioni della finestra ecc... Creo un pannello e gli aggiungo un bottone posizionandolo alle coordinate x=15 y=15. Di seguito intercetto l'evento wx.EVT_BUTTON per il bottone e lo associo al metodo onHelloWorld.
La definizione della finestra è praticamente finita, manca solo il codice che intercetta la chiusura della finestra e il metodo mostra che non fa altro che visualizzare la finestra sul desktop.

Sotto la dichiarazione della finestra c'è altro codice che definisce l'applicazione. Un wx.Frame da solo non può coesistere, wxPython richiede la scrittura di ulteriore codice che definisca un'applicazione wx.App.
Ho definito Applicazione che estende wx.App e che ridefinisce il metodo OnInit. OnInit crea la finestra e la posiziona come la principale dell'applicazione tramite il metodo SetTopWindow.
Quando viene eseguito il codice all'interno della condizione if __name__ == '__main__': viene costruito un nuovo oggetto Applicazione e viene lanciato il ciclo generale con il metodo MainLoop.

L'esempio qui sotto si riferisce alla versione 2.5. A questa versione sono state apportate diverse modifiche strutturali che la rendono incompatibile con i vecchi script realizzati per la 2.4.

Listato 2 - esempio di interfaccia grafica WxPython:
import wx

class Finestra(wx.Frame):
	
	def __init__(self):
		"""Costruttore della classe Finestra
		"""
		wx.Frame.__init__(self, None, -1, 'Ciao da wxPython',
			wx.DefaultPosition, wx.Size(220, 150))
		p = wx.Panel(self, -1)

		b = wx.Button(p, -1, 'Ciao mondo !')
		b.SetPosition((15, 15))
		
		self.Bind(wx.EVT_BUTTON, self.onHelloWorld, b)
		self.Bind(wx.EVT_CLOSE, self.onCloseWindow)

	def onHelloWorld(self, event):
		"""Stampa sullo standard output la stringa 'Hello world !'
		"""
		print 'Ciao mondo !'
		
	def onCloseWindow(self, event):
		"""Chiude l'applicazione alla chiusura della finestra
		"""
		self.Destroy()
		
	def mostra(self):
		"""Visualizza la finestra
		"""
		self.Show(True)


class Applicazione(wx.App):
	
	def OnInit(self):
		f = Finestra()
		f.mostra()
		self.SetTopWindow(f)
		return True

if __name__ == '__main__':
	a = Applicazione(0)
	a.MainLoop()
screenshot su Linux
Screenshot su Linux
screenshot su Mac OS X
Screenshot su Mac OS X
screenshot su Windows
Screenshot su Windows

PyGTK

La libreria PyGTK è un wrapper verso le famose librerie GTK. Le GTK sono famose perché utilizzate nello sviluppo del desktop Gnome. Sono molto stabili e per questo risultano un'ottima scelta per lo sviluppo di interfacce grafiche. Attualmente PyGTK è utilizzata da RedHat per la scrittura di tutti gli strumenti di amministrazione e per il programma di installazione Anaconda.

Uno dei vantaggi più grandi di questa libreria sta sicuramente nella possibilità di creare applicazioni con interfaccia nativa in Linux. Cambiando tema in Gnome cambierà anche l'aspetto delle vostre applicazioni. PyGTK ha un vasto assortimento di oggetti grafici che permettono di creare interfacce di tutti i tipi. Uno svantaggio è lo scarso supporto per Mac OS X, che non permette di avere un'interfaccia nativa. Bisogna infatti ricorrere ad un server X per far girare applicazioni GTK sotto Mac OS X. Non consiglierei, quindi, PyGTK per applicazioni che dovranno girare anche su Mac OS X, L'esempio che ho riportato qui sotto è stato testato con successo su Winodws XP e Fedora Core 3.

Anche l'esempio che ho realizzato con la PyGTK si avvale di una finestra ed un bottone con un evento associato. Si tratta della classe Finestra che estende la classe gtk.Window. La classe Finestra ha nel costruttore il codice per la personalizzazione della finestra stessa e la creazione del bottone tramite la classe gtk.Button. L'evento clicked, del bottone, viene collegato al metodo helloWorld, che al click dell'utente scriverà sulla console Ciao mondo !. Anche in questo esempio ho registrato l'evento di chiusura della finestra e gli ho associato la chiusura dell'applicazione con il codice gtk.main_quit().

In sostanza scrivere applicazioni con la libreria PyGTK è semplice e veloce e permette di realizzare applicazioni portabili su Windows e Linux senza nessun problema.

Listato 3 - esempio di interfaccia grafica PyGTK:
import gtk

class Finestra(gtk.Window):
	
	def __init__(self):
		gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
		self.set_title('Ciao PyGTK')
		self.resize(220,150)
		self.connect('destroy', self.chiudi)

		b = gtk.Button('Ciao mondo !')
		b.connect('clicked', self.helloWorld, None)
		b.show()
		
		fixed = gtk.Fixed()		
		fixed.put(b, 15, 15)
		fixed.show()
		
		self.add(fixed)
		
	def mostra(self):
		self.show()
		gtk.main()
		
	def helloWorld(self, widget, data=None):
		print 'Ciao mondo !'
		
	def chiudi(self, widget, data=None):
		gtk.main_quit()
		
if __name__ == '__main__':
	f = Finestra()
	f.mostra()
screenshot su Linux
Screenshot su Linux
screenshot su Windows
Screenshot su Windows

PyQT

La libreria PyQT permette di realizzare applicazioni sfruttando le librerie QT realizzate dalla Trolltech. Le QT sono famose perché utilizzate per lo sviluppo del desktop Linux KDE. Sono librerie C++ portabili su diversi sistemi operativi e sono molto utilizzate per lo sviluppo di applicazioni multipiattaforma interamente scritte in C++. Per esempio sono utilizzate per lo sviluppo della versione Linux del browser web Opera.

La PyQT è stabile e robusta, riccha di oggetti grafici e portabile su diverse piattaforme. Un esempio di applicazione scritta con la PyQT è Kodos, un programma per testare espressioni regolari molto potente. Qui sotto ho riportato un esempio di finestra realizzata con PyQT.

Listato 4 - esempio di interfaccia grafica PyQT:
from qt import *
import sys

class Finestra(QMainWindow):
	
	def __init__(self):
		QMainWindow.__init__(self)
		self.setCaption('Ciao da PyQT')
		self.setGeometry(100, 100, 220, 150)
		
		b = QPushButton('Ciao mondo !', self)
		b.setGeometry(15, 15, 100, 25)
		
		self.connect(b, SIGNAL("clicked()"), self.helloWorld)

	def helloWorld(self):
		"""Stampa sullo standard output la stringa 'Hello world !'
		"""
		print 'Ciao mondo !'
	
	def mostra(self):
		self.show()

if __name__ == '__main__':
	a = QApplication(sys.argv)
	f = Finestra()
	f.mostra()
	a.connect(a, SIGNAL("lastWindowClosed()"), a, SLOT("quit()"))
	a.exec_loop()
screenshot su Linux
Screenshot su Linux

PyObjC

Si tratta di una libreria specifica per l'ambiente Mac OS X, è un wrapper per il linguaggio Objective-C e il framework Cocoa. Cocoa è un framework introdotto con Mac OS X, che rende disponibile allo sviluppatore un set completo di librerie per lo sviluppo di applicazioni specifiche per Mac OS X. PyObjC permette l'integrazione con l'ambiente di sviluppo di Apple: Xcode e Interface Builder Richiede Python installato sulla macchina (da Panther in poi è installato di base) e i Developer Tools. Per sviluppare con PyObjC basta scaricare ed installare il pacchetto PyObjC. Per l'installazione, PyObjC necessita dei Developer Tools di Apple. Quest' ultimo ha bisogno di parecchio spazio su disco perché contiene tutto l'ambiente necessario per lo sviluppo di applicazioni per Mac OS X sia con Python sia con C, C++ e Objective-C.

Il vantaggio che porta questo tipo di approccio alle interfacce grafiche Python è chiaro: si tratta di un ambiente creato appositamente per lo sviluppo di applicazioni per Mac OS X e come tale permette di fare qualsiasi cosa che si potrebbe fare scrivendo il codice in C. L'ambiente permette di sviluppare applicazioni ad interfaccia grafica basandosi sul paradigma MVC. Il paradigma prevede tre componenti che interagiscono tra di loro:

  • Model - la parte che gestisce i dati.
  • View - la parte che visualizza i dati.
  • Controller - la parte che fa interagire gli altri due.

Sfruttando questo paradigma possiamo separare le tre componenti fondamentali, possiamo così astrarre la fonte dei dati dalla sua visualizzazione e non dobbiamo riscrivere da zero codice in caso cambi la fonte dei dati o cambi la loro visualizzazione. Le prestazioni di questa libreria sono molto vicine a quelle delle applicazioni native. Si crea l' interfaccia grafica con l'apposito strumento Interface Builder azzerando i tempi per la scrittura del codice per l'interfaccia. In pratica, si scrive una classe che fa da controller per l'interfaccia grafica appena realizzata con l'Interface Builder, si agganciano i vari oggetti (chiamati Outlets) e i vari eventi alla classe controller. Poi si scrive nel controller il codice che deve essere eseguito quando vengono scatenati gli eventi.

Qui sotto ho inserito il codice di un controller:

Listato 5 - esempio di interfaccia grafica PyObjC:
from Foundation import NSLog
from PyObjCTools import NibClassBuilder

NibClassBuilder.extractClasses("MainMenu")

class Controller(NibClassBuilder.AutoBaseClass):

	def clickBottone_(self):
		NSLog("Ciao mondo !")
screenshot su Mac OS X
Screenshot su Mac OS X
screenshot applicazione nel dock di Mac OS X
Screenshot applicazione nel dock di Mac OS X

Win32All

Si tratta di una libreria che permette l'accesso alle API di Windows e alle MFC. Come detto in precedenza, non è multipiattaforma, perchè strettamente legata al sistema operativo Windows. La libreria è stata scritta da Mark Hammond, sul suo sito potete trovare anche altre cose interessanti su Python. Non sono riuscito a trovare molte risorse ed esempi su questa libreria.

Conclusione

Per concludere possiamo dire che scrivere interfaccie grafiche con Python è molto divertente e molto veloce. La migliore libreria risulta wxPython ed è sicuramente la scelta più azzeccata per qualsiasi tipo di applicazione. Se la vostra applicazione dovrà girare solo sotto Linux sceglierei PyGTK o PyQT. Ovviamente da fan di Gnome io scelierei PyGTK :-) Ci sono moltissime risorse on-line sulle interfaccie grafiche realizzate con Python, articoli su moltissimi siti. Python si sta facendo largo in parecchie raltà commerciali dopo aver spopolato nell'ambito scientifico. Google è un esempio clamoroso di utilizzo commercilae di questo linguaggio. Qui sotto ho elencato alcune risorse da cui ho preso informazioni per scrivere questo articolo.

Riferimenti:

Bibliografia: