Guizero

Guizero è un framework per creare interfacce grafiche in python semplice da usare, multipittaforma e, a detta dei suoi sviluppatori, adatto anche ai bambini. Per tale ragione mi sembra lo strumento perfetto su cui soffermarsi per un tutorial adatto a un neofita come me.

La fonte da cui prendo i dati qui illustrati è il sito ufficiale del progetto (in inglese)

Prima di iniziare questo tutorial ovviamente si consiglia la lettura di quello di base del python

Installazione

Guizero è un pacchetto di python che va installato tramite pip per essere utilizzato, mediante il comando

pip3 install guizero

è possibile inoltre installare strumenti un po’ più avanzati per la gestione delle immagini mediante questo comando:

pip3 install guizero[images]

E’ possibile su linux installare guizero anche via apt (si rimanda per i pochi interessati al tutorial in inglese). Utilizzare in ogni caso un solo metodo di installazione.

Creazione di una singola finestra vuota

from guizero import App

app=App(title=”nuova app”)

app.display()  #questo crea solo una finestra con il titolo “nuova app”

Aggiungere un testo fisso

per aggiungere del testo fisso alla finestra basta fare una semplice modifica al codice:

from guizero import App, Text

app=App(title=”nuova app”)

messaggio= Text(app, text=”testo dentro la finestra”)

app.display()

Aggiungere un bottone premibile

E’ possibile anche aggiungere ad esempio un bottone che quando è premuto cambia il testo mostrato:

from guizero import App, Text, PushButton

def ChangeMessage(): #questa funzione viene chiamata quando si preme il bottone, è bene scrivere le funzioni evento prima di instanziare la app

….message.value(“hai premuto il bottone”)

app=App(title=”nuova app”)

messaggio= Text(app, text=”testo dentro la finestra”)

button=PushButton(app, text=”premimi”, command=ChangeMessage())

app.display()

Utilizzare i widgets

Ogni app fatta con guizero è composta da widgets interagenti.

Tutti i widget del programma vanno inseriti fra la funzione App() e la funzione app.display()

Aggiungere una finestra di input testo

testoinp=TextBox(app)  #ove app è l’istanza attiva della classe App definita da guizero e testoinp l’oggett

Visualizzazione dei widget a schermo

I seguenti metodi consentono di abuilitare/disabilitare o anche mostrare/nascondere le istanze dei widgets a schermo

nomeistanza.show() #mostra a schermo

nomeistanza.hide() #nasconde

nomeistanza.enable() #abilita

nomeistanza.disable() #disabilita

I widget possono essere anche distrutti mediante:

nomeistanza.destroy()

tuttavia si raccomanda di non usare questo metodo per evitare problemi

Finestre ulteriori

E’ possibile aprire sottofinestre da quella principale mediante Window()

sottofinestra=Window(app, title=”sottofinestra”)

#Ci si può poi riferire alla sottofinestra allo stesso modo della principale per metterci ulteriori widget: esempio

testo=Text(window,text=”questo testo comparirà nella seconda finestra”)

Mediante i metodi show() e hide() è possibile aprire e chiudere le sottofinestre

Se si vuole impedire di usare la finestra principale quando quella secondaria è aèperta è possibile modificare così la funzione show()

window.show(wait=True)

Layout

La disposizione degli elementi di un programma può essere definita automaticamente o mediante una griglia mediante questa singola riga di codice (una a scelta scritta dopo la dichiarazione della variabile app:

app = App(layout=“auto”)

oppure

app = App(layout=“grid”)

Se nessun layout è specificato di default vale l’impostazione “auto”

Per definire la posizione di un oggetto con il default auto bisogna specificare nella sua dichiarazione la variabile “align”. esempio:

testo_in_cima = Text(app, text=“in cima”, align=“top”)

Align può avere i seguenti valori: top, bottom, left, right

Se si usa lo stesso valore di align più volte di fila li oggetti verranno disposti in sequenza dal primo all’ultimo.

Le variabili “width” ed “height” permettono di definire le dimensioni dei widget. Specificando come valore “fill” riempiranno tutta la finestra lungo quella dimensione. Se si usa fill con più widgets lo spazio viene diviso equamente.

Se invece si usa il layout “grid” la posizione di un oggetto è definita dalle sue coordinate specificate nella variabile grid. Esempio:

testo_xy = Text(app, text=“in cima”, grid=[x,y]) #ove x e y sono i valori delle coordinate

All’interno di una griglia è anche possibile specificare la variabile align, per disporre più oggetti in sequenza nell’ambito della stessa coordinata. Esempio di form compilabile così creato:

etichetta_nome = Text(app, text=“Nome”, grid=[0,0], align=“left”)

nome = TextBox(app, grid=[1,0])

etichetta_cognome = Text(app, text=“Cognome”, grid=[0,1], align=“left”)

cognome= TextBox(app, grid=[1,1])

Mediante la griglia è anche possibile specificare che un widget ha una dimensone maggore di una cella:

testo_largo=Text(app,text=”testo largo”,grid[x,y,dx,dy])

#ove dx e dy sono le dimensioni oltre l’unità dell’oggetto lungo l’asse scelto.

Widget box

Mediante il widget box è possibile organizzare i widget in sottoinsiemi. Esempio:

scatola = Box(app, width=“fill”, align=“top”,border=true)

#se border è settato su true i bordi del widget saranno visibili

titolo = Text(scatola, text=“titolo”, align=“top”)

testosotto=Text(scatola,text=”testo di sotto”, align=”bottom”)

E’ possibile anche inserire widget box dentro altri widget box.

Pop-up

Queste funzioni possono essere inserite nel programma per aprire diversi tipi di popup a schermo. In questi esempi la variabile app si riferisce sempre al programma:

app.warn(“titolo”,”testo”)

#popup con icona di avvertimento

app.info(“titolo”,”testo”)

#popup con icona di informazione

app.error(“titolo”,”testo”)

#popup con icona di errore

app.yesno(“titolo”,”testo”)

#popup che consente di scegliere con 2 bottoni si o no. Se viene premuto si ritorna true, se viene premuto no ritorna false

app.question(“titolo”,”testo”,valore iniziale=”abcde”)

#popup con possibilità di introdurre un testo che viene restituito dalla funzione premendo il tasto OK. se nessun testo viene inserito ritorna il valore None

app.select_file(“titolo”, folder=” *. *”. filetypes=[]”tutti i formati”,”*.*”]], save=false. filename=”nomefile”)

#permette di selezionare un file. Se save è settato su true si commuta in “salva con nome”

app.select_folder(“titolo”, folder=”\percorso\cartella”)

#permette di selezionare una cartella

app.select_color(color=None)

#permette di selezionare un colore, restituito come output nel formato #rrggbb (esadecimale). Premendo annulla restituisce None.

Altre funzioni importanti:

app.destroy()

#chiude il programma se usata sull’istanza principale

app.when_closed  #vale true se si cerca di chiudere il programma, utile per programmmare un popup di conferma chiusura

Dimensioni:

Come detto prima le dimensioni dei widget possono essere specificate mediante le variabili width ed height; Usando “fill” come impostazione il widget riempie tutto lo spazio disponibile, mentre usando un valore numerico si può definire la dimensione del widget in modo specifico, tuttavia l’unità di misura varia da widget a widget e non tutti accettano il settaggio fill. Qui sotto un riassunto breve:

Box accetta fill e le dimensioni sono espresse in pixel. Se si sceglie di settare vanno specificati sia width sia height

Buttongroup accetta fill e le dimensioni sono espresse in caratteri. Height viene diviso per il numero di bottoni

Checkbox accetta fill e le dimensioni sono espresse in caratteri

Combo accetta fill e le dimensioni sono espresse in caratteri

Listbox accetta fill e le dimensioni sono espresse in pixel

Picture non accetta fill e le dimensioni sono espresse in pixel (vedremo meglio quando si parlerà di immagini)

PushButton accetta fill e le dimensioni sono espresse in caratteri

PushButton con immagini non accetta fill e le dimensioni sono espresse in pixel

Slider accetta fill e le dimensioni sono espresse in pixel

Text accetta fill e le dimensioni sono espresse in caratteri

TextBox accetta fill e le dimensioni sono espresse in caratteri. E’ possibile esprimere solo width

Waffle non accetta fill e le dimensioni sono espresse in pixel

Colori

In guizero i colori sono definibili in 3 modi:

  • per nome
  • in esadecimale (come già visto prima, questa è la modalità standard con cui il programma gestisce i colori fra le funzioni)
  • in decimale

Ad esempio per definire il colore dello sfondo (rosso)  della finestra:

app=App(bg=”red”)

app=App(bg=”#ff0000″)

app=App(bg=(255,0,0))

Il colore di un testo può essere definito così:

text=Text(app,text=”testo verde”)

text.text_color=”green”

#se text.text_color=None il colore sarà quello di default

qui è disponibile un elenco dei nomi dei colori supportati

qui trovate un convertitore fra i vari modi per definire i colori

Qui sotto le definizioni nei 3 modi dei colori più comuni:

  • white = #ffffff (255,255,255)
  • black = #000000 (0,0,0)
  • red = #ff0000 (255,0,0)
  • green = #00ff00 (0,255,0)
  • blue = #0000ff (0,0,255)
  • yellow = #ffff00 (255,255,0)

Immagini

Inserire un’ immagine in un app è semplicissimo. Ricordate da installare pillow da pip o da apt per un migliore e più completo supporto a diversi formati, come detto in introduzione.

from guizero import App, Picture

app=App()

immagine=Picture(app, image=”immagine.jpg”)

app.display()

E’ necessario avere pillow sul sistema per riscalare un’immagine all’interno del programma, in caso contrario questa sarà tagliata. Pillow consente abche di vedere le GIF animate.

Loop, cicli e sleep

Quando si vuole modificare nel tempo una GUI di guizero non è possibile dichiarare ad esempio un ciclo while all’interno dell’interfaccia per creare un cronometro, in quanto le GUI sono già di per se cicli infiniti che si chiudono con app.destroy(). Se farete questo il programma andrà quindi in crash.

Per lavorare su variazioni periodiche la cosa migliore è creare una funzione di callback come quella qui in esempio:

from guizero import App, Text

def contatore():

….text.value=int(text.value)+1

app=App()

text=Text(app,text=”1″)

text.repeat(1000, contatore) #questo ripete la funzione contatore ogni 1000 ms

app.display()

Eventi

E’ possibile che il programma venga impostato per eseguire qualunque azione all’accadere di alcuni  eventi all’interno dell’interfaccia grafica. Questi sono gli eventi disponibili in guizero richiamabili mediante metodo al widget scelto all’interno di funzioni:

widget.when_clicked (clic del mouse)

widget.when_double_clicked (doppio clic del mouse)

widget.when_left_button_pressed (pressione del tasto sinistro del mouse)

widget.when_left_button_released (rilascio del tasto sinistro del mouse)

widget.when_right_button_pressed (pressione del tasto destro del mouse)

widget.when_right_button_released (rilascio del tasto destro del mouse)

widget.when_key_pressed (pressione di qualunque tasto sulla tastiera)

widget.when_key_released (rilascio di qualunque tasto sulla tastiera)

widget.when_mouse_enters (il puntatore del mouse entra nel widget)

widget.when_mouse_leaves (il puntatore del mouse abbandona il widget)

widget.when_mouse_dragged (il puntatore del mouse viene trascinato sul widget)

widget.when_resized (quando il widget viene ridimensionato)

Esempio

from guizero import App, Text

def cambiacolore():

….text.text_color=”red”

app=App()

text=Text(app,”testo colorato”)

text.text_color=”green”

text.when_double_clicked=cambiacolore

app.display()

Usare i widget Tkinter assieme a guizero

I due tipi di widget possono essere usati assieme ed è possible anche usare i metodi tkinter nei widget guizero