Welcome, guest | Sign In | My Account | Store | Cart

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)

Python, 115 lines
  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()