The behaviour of applications sometimes depends on various parameters that can be chosen by the user through some GUI. Quite often, these parameters need take value in a predefined set. Parameters include for instance:
- The number of replications for a simulator.
- Dates of beginning/end of sample for time series access/plot.
- Log writing
This recipe assumes that
- Such parameters are stored in a dictionary. Values in the dictionnary are used as initial values for the parameters.
- Values are "singleton", i.e non iterable (although they may be strings).
- When a value is a list instance, its content represent the set of possible values The recipe offers a simple way to edit the values in a Tkinter Frame, by adding proper widget to it (constrained value are menubutton while unconstrained values are edit widgets).
This is done by the function apply(frame,dict,position), which adds to the Tkinter frame the necessary widgets to edit the dictionary dict. Widgets are placed using grid (hence the frame needs use grid() too) and span on two columns. topleft position (x,y) in grid is specified using position= (x,y,0,0)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | """
DICTIONNARY INTERFACE FOR EDITING VALUES
creates labels/edits/menubutton widgets in a TkFrame to edit dictionary values
use: apply(frame,dict,position)
"""
import Tkinter as tk
def cbMenu(controlV,value,btn= None):
controlV.set(str(value))
if not (btn== None):
btn.config(text= str(value))
def updateMB(ctrlV, value):
ctrlV.set(value)
def doLambda(f,*args):
"""Tips: Create lambda within for loop with fixed local variable
without interference across iterations"""
def g(): return f(*args)
return g
def apply(root,d,pos):
"""Creates interface for dictionnary d in root at given grid position """
"TODO: repercuter kwargs"
(x,y,w,h)= pos
lbs= []
saisies= dict()
entries= dict()
for (n,(k,v)) in enumerate(d.iteritems()):
assert (k not in saisies)
l= tk.Label(root,text=str(k))
l.grid(row=n+x,column=y)
if isinstance(v,list):
"""value= list => multiple choice => use menubutton"""
#saisies[k]= tk.StringVar(name=str(n),value= str(v[0]))
saisies[k]= tk.StringVar(value= str(v[0]))
ent=tk.Menubutton(root,textvariable=saisies[k],relief="sunken")
ent.m=tk.Menu(ent,tearoff=0)
ent.config(menu=ent.m)
for (kk,possible) in enumerate(v):
possibleSaved= "%s" %possible
ent.m.add_command(label=str(possible), command= doLambda(updateMB,saisies[k],str(d[k][kk]) ) )
print possible
else:
"""value is not a list => classical edit => use Entry"""
#saisies[k]= tk.StringVar(name=str(n),value= str(v))
saisies[k]= tk.StringVar(value= str(v))
ent= tk.Entry(textvariable=saisies[k])#,width=30)
ent.grid(row=n+x,column=y+1)
entries[k]= ent
return saisies
def get(strVarDict):
d= {}
for (k,v) in strVarDict.iteritems():
#try: v= float(v)
#except: pass
d[k]=v.get()
return d
def main():
"EXAMPLE"
root = tk.Tk()
#d= {'oui':1, 'non':'non'}
d= {'oui':1,'a':'b', 'non':['?','!non'],'mode':[1.1,2.1,3.1]}
v= tk.StringVar(value= "Open File Dialog")
m=tk.Menubutton(root,textvariable=v,relief="raised")
m.grid(row=2,column=1)
mm=tk.Menu(m,tearoff=0)
tk.Button(root, textvariable=v, command=lambda:v.set('oui')).grid(row=1,column=1)
mm.add_command(label="go", command=lambda: cbMenu(v,"non"))
m.config(menu=mm)
s= apply(root,d,(0,2,0,0))
print isinstance(d, dict)
root.mainloop()
#print d
print s
for (k,v) in s.iteritems():
print str(k), '->',str(v.get())
def testindependance():
root = tk.Tk()
d= {'oui':1,'a':'b', 'non':['?','!non'],'mode':[1.1,2.1,3.1]}
s= apply(root,d,(0,2,0,0))
dd= {'oui':1,'a':'b', 'non':['?','!non'],'mode':[1.1,2.1,3.1]}
ss= apply(root,dd,(0,5,0,0))
print "s =",s
print "ss=",ss
print isinstance(d, dict)
root.mainloop()
#print d
#print s
for (k,v) in s.iteritems():
print str(k), '->',str(v.get())
print "-"*10
for (k,v) in ss.iteritems():
print str(k), '->',str(v.get())
print "="*10
print get(s)
print get(ss)
if __name__ == '__main__':
main()
#testindependance()
|