Python e Kivy, il file kv

by Marco C on

Nell’articolo precedente Python e Kivy la prima interfaccia grafica abbiamo iniziato ad analizzare il file .py della nostra prima applicazione. Ora tocca al file che si occupa della grafica, in linguaggio KV.

Il linguaggio KV è un linguaggio molto simile a quello dei CSS che permette di tenere separata la gestione dell’interfaccia grafica da quello che è l’applicazione logica.

Il file my.kv

#:kivy 1.9.0

<MyLabel@Label>:
    #text: ctx.text if hasattr(ctx, 'text') else 'Testo vuoto'
    font_size: 24
    markup: True
    color: (0, 0, 0, 1)
    size_hint_y: .3
<TInput@TextInput>:
    multiline: False
    size_hint_y: .3
    font_size: 24
<XInput@TInput>:
    foreground_color: (0, 0, 0.6, 1)#colore del testo 
    input_filter: "int"
    write_tab:False
<CInput@CapitalInput>:
    multiline: False
    hint_text_color:(0.8,0.8,0.8,1)
    hint_text:"Testo in grassetto"
<CalcButton@Button>:
    the_root: self.parent.my_root
    on_release: self.the_root.esegui(self.text)
    size_hint: (0.5, 0.5)

<gui>:
	orientation: "vertical"

    canvas:
        Color:
            rgba: 0.8, 0.8, 0.8, 1
        Rectangle:
            # self here refers to the widget i.e BoxLayout
            pos: self.pos
            size: self.size
    MyLabel:
        text: 'Primo Numero'

    XInput:
        id:primo

    MyLabel:
        text: 'Secondo Numero'

    XInput:
        id:secondo

    BoxLayout:
        my_root:root
        CalcButton:
            text:"+"
        CalcButton: 
            text: '-'
    BoxLayout:
        orientation: "vertical"
        canvas:
            Color:
                rgba: 0.596, 0.921, 0.658,1 
            Rectangle:
                # self here refers to the widget i.e BoxLayout
                pos: self.pos
                size: self.size
        MyLabel:
            text: 'risultato'
            id:myresult

Analizziamo le singole parti

#:kivy 1.9.0

Come prima, semplice semplice, importiamo il modulo kivy ed indichiamo la versione minia d’uso

<MyLabel@Label>:
    #text: ctx.text if hasattr(ctx, 'text') else 'Testo vuoto'
    font_size: 24
    markup: True
    color: (0, 0, 0, 1)
<TInput@TextInput>:
    multiline: False
    size_hint_y: .3
    font_size: 24
<XInput@TInput>:
    color:(0,0,0,1)
    input_filter: "int"
    write_tab:False
<CInput@CapitalInput>:
    multiline: False
    hint_text_color:(0.8,0.8,0.8,1)
    hint_text:"Testo in grassetto"
<CalcButton@Button>:
    on_release: self.parent.my_root.esegui(self.text)
    size_hint: (0.5, 0.5)

Con questo elenco vado a definire 5 classi differenti per gestire 3 moduli differenti: Label, ITextInput e Button.
Non è necessario utilizzare questo sistema ma è altamente consigliato se si vuole mantenere lo stesso stile grafico per tutti i campi, assegnando ad ogni modulo uno stile differente.
La classe CInput, fa riferimento alla classe CapitalInput definita del file gui.py e si occupa di gestire stilisticamente tutti i campi CInput
La classe XInput invece è una classe di una classe. Ovvero partendo da TInput che definisce stilisticamente i Text Input, assegno dello specifico stile ad altri input cosi da poterli differenzire, in questo caso, quello che a me interessava era la definizione di input_filter per poter accettare solo numeri.
CalcButton invece fa riferimento ai bottoni utilizzati e contiene la chiamata alla funzione esegui presente nel file .py
Andremo ad analizzare il comando on_release quando inseriamo i bottoni nella GUI

<gui>:
	orientation: "vertical"

    canvas:
        Color:
            rgba: 0.8, 0.8, 0.8, 1
        Rectangle:
            # self here refers to the widget i.e BoxLayout
            pos: self.pos
            size: self.size

Passiamo alla definizione della Gui principale. In questo caso richiamo la classe con lo stesso nome definito nel file .py e avendo già indicato il tipo di layout utilizzato, vado a darne le definizioni.
Poichè di base il layout ha colore nero, ed io preferisco uno sfondo chiaro, utilizzo il modulo canvas per creare un rettangolo delle dimensioni della box e lo coloro in grigio. Per farlo, abituato agli esadecimali dei css o agli rgba su scala 255 e per non farlo a mano ogni volta mi appoggio ad un servizio online moldo comodo: uicolor.xyz

MyLabel:
        text: 'Primo Numero'

    XInput:
        id:primo

    MyLabel:
        text: 'Secondo Numero'

    XInput:
        id:secondo

Sullo stesso livello di indentazione (ricordiamoci che python usa questo metodo per gestire genitori e figli) inserisco i 4 moduli base sfruttando le classi create MyLabel e Xinput e dichiarando solamente la definizione text per MyLabel e la definizione id per XInput necessaria per essere richiamata nel file .py

BoxLayout:
        my_root:root
        CalcButton:
            text:"+"
        CalcButton: 
            text: '-'

Vediamo ora come inserire i bottoni. A livello stilistico li abbiamo già definiti tra le variabili iniziali dove abbiamo definito anche il loro comportamento al rilascio (bind=on_release) ma visualizzarli uno sotto l’altro starebbero male, quindi, creiamo un ulteriore Box, questa volta organizzato orizzontalmente (di default ‘horizontal’) senza andare a modificarne la definizione.
Quindi dichiariamo la variabile my_root che fa riferimento alla root(quindi alla classe che stiamo gestendo graficamente e a tutte le funzioni in essa contenute) per essere richiamata dai bottoni.
Si perchè la classe CalcButton non è una classe definita anche nel file .py e quindi gestibile in python, di conseguenza i l’azione eseguita sui bottoni definiti da questa classe, chiamerebbero dell funzioni inesistenti.
Poichè i bottoni chiamano self.parent.my_root.esegui() di conseguenza e a livello gerarchico diciamo al bottone di chiamare: se stesso, poi il genitore (quindi il box che fa parte della classe Gui definita in .py) e la variabile in esso contenuta my_root che e simbolicamente riferita alla classe Gui e quindi la funzione esegui contenuta nella classe Gui

 BoxLayout:
        canvas:
            Color:
                rgba: 0.596, 0.921, 0.658,1 
            Rectangle:
                # self here refers to the widget i.e BoxLayout
                pos: self.pos
                size: self.size
        MyLabel:
            text: 'risultato'
            id:myresult

Come ultimo passo visualizziamo il campo Label ove inserire i risultati delle operazioni.
Sempre sfruttando il concetto di indentazione, per non inserire il risultato accando ai bottoni ma sotto, riparto da un livello superiore e quindi parificato al BoxLayout precedente ed ai Label e TextInput precedenti. Inserisco un utleriore Box Layout per poter gestire lo sfondo di questo particolare box e come fatto precedentemente, inserisco tramite canvas un rettangolo colorato ed al suo interno un MyLabel con un id necessario per essere utilizzato nel file .py

A questo punto l’applicazione funziona.

Leggi il contenuto originale su Kreatore.it - blog

Written by: Marco C