.. _tutor/pagina/dataformula: 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. .. raw:: html
Esempio di calcolo area di un triangolo
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. .. raw:: html
Esempio di bilancio personale
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'. .. raw:: html
Esempio più complesso : colorMaker
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 : .. image:: /_static/images/00_colormaker.png :width: 240px 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 `_