DataFormula¶
Un dataFormula è un elemento attivo della pagina che puo ricevere vari parametri sia come costanti che come riferimenti (path attivi e passivi) al datastore.
La sua forma generica è:
pane.dataFormula(path, formula, par1=..., par2=...)
Al variare del valore di uno dei parametri la formula viene ricalcolata e il risultato scritto nel datastore al path desiderato.
Per prima cosa creiamo un titolo, un box e un formbuilder:
def main(self,root,**kwargs):
root.h1('Triangle Area',text_align='center')
box=root.div(margin='5px',datapath='triangle',
border='1px solid silver')
fb = box.formbuilder(cols=3,fld_width='80px')
Definiamo all’interno del formbuilder due numberTextBox che serviranno per inserire base e altezza del triangolo:
fb.numberTextBox('^.base',lbl='Base',default_value=0)
fb.numberTextBox('^.height',lbl='Height',default_value=0)
Mettiamo poi un numberTextBox con attributo readOnly=True che prenderà il proprio valore al path “.area”:
fb.numberTextBox('^.area',lbl='Area',readOnly=True)
Infine mettiamo il dataFormula:
fb.dataFormula('.area','b*h/2', b='^.base', h='^.height')
Da notare che il primo parametro, ovvero il path di destinazione NON ha un simbolo di puntatore mentre sia b
che h
ricevono il valore da path relativi preceduti dal simbolo ^.
Ogni volta che cambiamo il valore di base o di altezza la formula viene ricalcolata e il valore di area aggiornato.
Iniziamo come sempre dal main dove mettiamo un box con un titolo e un formbuilder:
def main(self,root,**kwargs):
box=root.div(border='1px solid gray', width='400px',color='#666',
datapath='balance',margin='5px',rounded=4)
box.div('Personal Balance',text_align='center',font_size='24px')
fb = box.formbuilder(cols=1)
Il primo valore che andiamo a mettere sono le nostre entrate mensili:
fb.numberTextBox('^.income',lbl='Income',width='100px',default_value=0)
Abbiamo poi definito un metodo expensesGroup
che ci permette di definire un insieme di voci di spesa e che
usiamo 3 volte per altrettanti gruppi:
self.expensesGroup(fb,datapath='.home',title='Home expenses',
items='rent,electricity,internet,cleaning,insurance')
self.expensesGroup(fb,datapath='.work',title='Work expenses',
items='brushes,canvas,colors')
self.expensesGroup(fb,datapath='.personal',title='Personal expenses',
items='food,newspapers,transport,restaurant,cinema')
Mettiamo poi un numberTextBox readOnly per totalizzare le spese e la relativa formula di calcolo:
fb.numberTextBox('^.total_expenses',lbl='Total expenses',width='100px',
readOnly=True)
fb.dataFormula('.total_expenses','home+work+personal',
home='^.home.total',
work='^.work.total',
personal='^.personal.total')
Ultimo elemento sarà il saldo e la relativa formula:
fb.numberTextBox('^.balance',lbl='Balance',width='100px',
background='lightyellow',
color='^.balance_color',font_weight='bold',
readOnly=True)
fb.dataFormula('.balance','income-total_expenses',
income='^.income',
total_expenses='^.total_expenses')
Notiamo infine un dataFormula usato per calcolare il colore con cui mostrare il saldo:
fb.dataFormula('.balance_color',
"(balance>100)?'green':'blue'",
balance='^.balance',
_if='balance>0', _else="'red'")
Questo dataFormula introduce il parametero _if
che offre la possibilità
di condizionare la formula e il parametro _else
che fornisce l’espressione da usare
nel caso la _if
non sia soddisfatta.
Vediamo ora invece il metodo expensesGroup
che riceve il formbuilder, datapath da usare, un titolo e una lista di voci da chiedere:
def expensesGroup(self,fb,datapath=None,title=None, items=None):
Nel formbuilder ricevuto mettiamo un div destinato a contenere un formbuilder innestato. Il div userà il datapath ricevuto mentre il formbuilder innestato aggiungerà a sua volta un datapath='.detail'
per i valori che andremo a digitare:
fb=box.formbuilder(cols=1,datapath='.detail' ,
fld_width='50px',lbl_width='100px',
border_spacing='2px')
Andiamo ora a prendere le voci dalla lista splittata sulla “,”:
for item in items.split(','):
fb.numberTextBox(value='^.%s' % item,default_value=0,
lbl_font_style='italic',
lbl=item.capitalize())
Per ogni voce specifichiamo un path relativo uguale al suo nome e mettiamo una label uguale al nome con la prima lettera maiuscola. Mettiamo anche che il valore di default è 0.
Ora dobbiamo calcolare la somma dei valori digitati e quindi mettiamo:
box.dataFormula('.total','detail.sum()', detail='^.detail')
Da notare che abbiamo posizionato il dataFormula non nel formbuilder
(che opera a livello di datapth=”.detail”), ma nel box
che invece ha come datapath quello del gruppo di spese. Infatti il nostro dataFormula riceve come parametro detail='^.detail'
e quindi all’interno dello script la variabile detail
conterrà tutta la bag dei valori del gruppo. Usiamo la funzione sum delle bag per sommare i valori di tutti i nodi della bag detail
ricevuta.
Da notare che il dataFormula scatterà per qualsiasi cambiamento all’interno del path “.detail” e quindi non appena cambiamo un valore la somma viene eseguita e il risultato messo al path “.total”.
Ora mettiamo un altro elemento nel formbuilder per mostrare il totale:
fb.numberTextBox('^.#parent.total',width='50px',
background='lightyellow',
lbl_font_weight='bold',
readOnly=True,lbl='Total')
Il numberTextBox che mettiamo per mostrare il valore calcolato prende il proprio valore al path '^.#parent.total'
. #parent è un elemento di path speciale che procede a ritroso nella gerarchia dello store e quindi, dato che il formbuilder sarebbe al path “.detail”, usando “#parent” ci portiamo a livello superiore dove si trova il valore “.total”.
Lo scopo di questo esempio è di mostrare come usare i path relativi e i dataFormula per costruire degli slider che configurino i colori di un div.
Come al solito partiamo dal main e costruiamo un box che contiene un formbuilder:
def main(self,root,**kwargs):
box=root.div(border='1px solid gray', width='380px', color='#666',
datapath='colormaker',margin='5px',rounded=4)
box.div('Color Maker',text_align='center',font_size='24px')
fb = box.formbuilder(cols=4,lblpos='T',lblalign='center')
A differenza dei formbuilder visti fin ora, questa volta usiamo l’attributo lblpos =”T” posiziona le etichette sopra i campi.
Procediamo ora ad inserire nel formbuilder 3 div che definiscono dei datapath relativi e le relative etichette “Background” , “Color” e “Shadow”. Tali div verranno poi passati al metodo self.colorRgb che provvederà a costruire all’interno del div ricevuto i tre slider per variare le componenti RGB:
self.colorRgb(fb.div(datapath='.bkg',lbl='Background'))
self.colorRgb(fb.div(datapath='.color',lbl='Color'))
self.colorRgb(fb.div(datapath='.shadow',lbl='Shadow'))
Infine posizioniamo nel formbuilder un div i cui colori sono definiti dalla posizione dei cursori degli slider:
fb.div('Test', padding='6px',font_size='30px',margin='10px',
width='100px',height='100px',rounded=8,
background_color='^.bkg.rgb',
color='^.color.rgb',
shadow_color='^.shadow.rgb',
shadow='4px 4px 8px')
Notiamo che background_color, color e shadow_color sono collegati al valore “.rgb” dei rispettivi path relativi.
Veniamo ora al metodo colorRgb
. Costruiamo un altro formbuilder che, come quello visto in precedenza, avrà le etichette posizionate sopra ai valori:
def colorRgb(self,pane):
fb = pane.formbuilder(cols=3,lblpos='T',lblalign='center',
fldalign='center', lbl_font_weight='bold')
Procediamo ora a chiamare 3 volte il metodo colorSlider passando il formbuilder stesso, e la componente di colore:
self.colorSlider(fb, value='^.red', component='red')
self.colorSlider(fb, value='^.green', component='green')
self.colorSlider(fb, value='^.blue', component='blue')
Notiamo che i valori vanno a path relativi '^.red'
, '^.green'
e '^.blue'
.
Mettiamo ora un dataFormula che partendo dalle 3 componenti di colore costruisca una stringa del tipo RGB(xx,yy,zz) e la metta al path “.rgb”:
fb.dataFormula('.rgb',"'rgb(+'+red+','+green+','+blue+')'",
red='^.red',blue='^.blue',green='^.green',
_onStart=True)
Il parametro `_onStart=True` richiede al sistema di eseguire il calcolo non solo alla variazione dei valori preceduti da ^ ma anche al caricamento della pagina. In questo modo anche al caricamento vengono subito caricati i colori.
Può sembrare superfluo ricordare che in realtà ci sono 9 cursori e 3 dataFormula perchè il metodo colorRgb
è chiamato 3 volte.
Resta solo ora da esaminare il metodo colorSlider
che costruisce uno
slider verticale opportunamente configurato per fornire valori tra 0 e 255 e per avere un valore iniziale random in questo range.
Si noti che i path nel datastore sono su due livelli :
Grazie ai path relativi è possibile riusare i metodi di costruzione e il codice è molto più compatto e manutenibile.
Per i dettagli sui parametri e sulla sintassi del widget dataFormula si rimanda all’apposita sezione sulla Widgetpedia