Python e Kivy, la prima interfaccia grafica

Torno dopo qualche tempo a parlare di Python e questa volta lo faccio per introdurre Kivy un framework grafico compatibile su più sistemi tra i quali anche Android ed IOS.

E proprio per questo motivo che ho lasciato, o meglio, cerco di lasciare l’ottimo e semplice Tkinter per approdare anche nel mondo mobile.

Iniziamo con il dire che la mia intenzione in questo articolo o serie di articoli (adesso decido come struttorarla) è quella di meemorizzare i processi base dell’uso di questo framework.
Per farlo ho prima studiato un attimimo le API di Kivy che sono ottimamente documentate in inglese quindi procedendo a tentativi e seguendo quanto ormai già disponibile online ho realizzato una prima semplicissima GUI e non il classico “Hello World” che si trova ormai in tutte le salse.

Il risultato finale

Una piccola applicazione che si occupa di sommare o sottrare due numeri, come una calcolatrice estremizzata al massimo.
Le caratteristiche principali:

  • i campi input devono accettare solo numeri
  • deve avere diversi colori
  • in base al pulsante premuto eseguo due azioni diverse
  • se non inserisco valori allerto l’utente
  • stampo il risultato in bella vista

Partiamo dal codice in Python: il file gui.py

#!/usr/bin/python3

import kivy
kivy.require('1.9.1')

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.logger import Logger
from kivy.config import Config
##set window no resizable
Config.set('graphics','resizable',0)
Config.set('graphics','width',200)
Config.set('graphics','height',400)

#questa classe presa dagli esempi mi serve per generate IntInput
class CapitalInput(TextInput):

        def insert_text(self, substring, from_undo=False):
            s = substring.upper()
            return super(CapitalInput, self).insert_text(s,
 from_undo=from_undo)

class gui(BoxLayout):

    def esegui(self,expression):
        if self.ids.primo.text !="" and self.ids.secondo.text !="":
            primo= self.ids.primo.text
            secondo=self.ids.secondo.text
            self.stampa(eval(primo+expression+secondo))
        else:
            self.stampa("Nessun numero")

    def stampa(self,text):
        Logger.info('title:'+str(text))
        self.ids.myresult.text=str(text)

class MyApp(App):

    def build(self):
        return gui()

if __name__ == '__main__':
    MyApp().run()

Questo è tutto il codice, analizziamolo velocemente

#!/usr/bin/python3

Piu semplice di cosi: la chiamata all’interprete Python3

import kivy
kivy.require('1.9.1')

Le prime righe si occupano di importare il framework di kivi con la relativa versione minima per il funzionamento

from kivy.app import App
from kivy.logger import Logger

Ora importiamo i moduli principali di Kivy (App) che permette il funzionamento del sistema e il Logger ovvero un gestore di Log molto utile ma non indispensabile all’applicazione in se.

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput

Questi tre moduli sono invece indispensabili per il funzionamento dell’applicazione. Come è facile intuire il secondo modulo serve per inserire del testo mentre il primo è utilizzato per definire come verrà gestito il layout della gui principale

from kivy.config import Config
##set window no resizable
Config.set('graphics','resizable',0)
Config.set('graphics','width',200)
Config.set('graphics','height',400)

Importando il modulo Config posso modificare i parametri principali di come viene visualizzata la Gui, in questo caso ho scelto di impedire il ridimensionamento della finestra assegnando delle dimensioni fisse.

class CapitalInput(TextInput):

def insert_text(self, substring, from_undo=False):
s = substring.upper()
return super(CapitalInput, self).insert_text(s,
from_undo=from_undo)

Questa classe in realtà non serve ai fini dell’applicazione ma mi è tornata utile per capire come modificare il testo inserito nei campi input. La richiesta del modulo TextInput è legata a questa funzione, eliminandola (non altera il funzionamento del programma) si può eliminare la richiesta del modulo TextInput

Ora facciamo un piccolo salto in fondo al file:

if __name__ == '__main__':
    MyApp().run()

Questa condizione è indispensabile per la chiamata principale al funzionamento dell’app. Un po come in Tkinter era il .mainloop().
Da notare che è indispensabile l’aggiunta di App legato al nome della funzione.

class MyApp(App):
    def build(self):
        return gui()

Ed ecco la classe vera e propria che da il via a tutto. All’interno di questa classe potrebbero essere definite anche altre funzioni dedicate a gestire la Gui e penso (ma questo devo ancora capirlo e confermarlo) gestire altre funzioni in generale.

class gui(BoxLayout):

    def esegui(self,expression):
        if self.ids.primo.text !="" and self.ids.secondo.text !="":
            primo= self.ids.primo.text
            secondo=self.ids.secondo.text
            self.stampa(eval(primo+expression+secondo))
        else:
            self.stampa("Nessun numero")

    def stampa(self,text):
        Logger.info('title:'+str(text))
        self.ids.myresult.text=str(text)

Per utlimo ma più importante vediamo la classe che controlla la Gui e che le da vita.
Notiamo che viene inizializzata con la variabile BoxLayut e questo ci fa capire che la finestra principale verrà aperta con questo metodo di gestione del layout. Ce ne sono altri… basta consultarli
Creiamo quindi le fue funzioni, anche se ne basterebbe una, per gestire in modo separato le azioni:

execute viene chiamata alla pressione di uno dei pulsanti di somma o sottrazione e acquisisce il valore dei due campi input.
In base al tasto premuto, esegue il calcolo
Se non vengono inseriti valori prepara un messaggio di avviso

stampa si occupa di reinviare alla Gui il valore passatole, sia esso il risultato dell’operzione o un messaggio di avviso

L’interfaccia grafica

Volendo gestire l’applicazione seguendo il modello MCV con Kivy è necessario utilizzare un file separato per gestire la grafica. Un po come avviene in Html con i CSS.
Nel nostro caso il file avrà estensione .kv ed il nome dovrà essere quello dell’applicazione principale senza l’estensione App:

class MyApp(App) -> my.kv

Andiamo ad analizzarlo nell’articolo Python e Kivy, il file KV