Tkinter widgets: Write options *and* option tags dynamically from dictionary?

Laura Creighton lac at strakt.com
Wed Feb 6 18:23:55 CET 2002


Johannes Eble writes:
> Hello Laura,
> 
> thanks again for your explanations.
> 
> Now I have another problem:
> 
> I want to use my own widgets in the same scheme. For example, let's
> say I have created the widget
> 
> LabelEntry
> 
> which just combines a label and an entry side by side in a row. The
> widget inherits from Frame:
> 
> class LabelEntry(Frame):
>     """Valid options: labelText, padx, pady"""
>     def __init__(self, master=None, labelText='', padx=4, pady=4):
>         Frame.__init__(self, master)
>         self.label = Label(self, text=labelText)
>         self.entry = Entry(self)
>         self.label.pack(side=TOP, anchor=W)
>         self.entry.pack(side=TOP, anchor=W, padx=padx, pady=pady)
> 
> This doesn't work together with an optionDict={'labelText':'hello',
> 'padx':'6'}
---------------------------------------------------^^^^^^^^

That is your problem.  Tkinter labels want to get their text
set with text='hello', not labelText='hello'

You have to make some design decisions here.  If you want to pass one big
dictionary, you will then have to unpack it, parse it, and generate
the correct keys for the correct widgets.  This is do-able; it is
what PMW does.  But I didn't like that approach.  I just use 2 dictionaries.

You also mention:
>But then, how do I handle default values, and how do I ensure that the
>objects are created with the right parameters? Maybe I should use a
>local dictionary.

[snip]

>Is there an elegant solution to this problem?

Well, I don't know if you would call this elegent but ...


from __future__ import nested_scopes
import Tkinter

class LabelledWidget(Tkinter.Frame):
    def __init__(self, parent, widgetName=Tkinter.Entry,
                 labelDict={}, widgetDict={}, **frameDict):
        
        Tkinter.Frame.__init__(self, parent, **frameDict)

        """
        let us say that you always want the label to be written on a
        cyan background in purple letters, unless you ask differently.
        The widget you just want on a green background.
        """
        
        ldefaults={'bg': 'cyan', 'fg' : 'purple'}
        wdefaults={'bg': 'green'}
        # overwrite any of the defaults with the dictionary you passed
        ldefaults.update(labelDict)
        wdefaults.update(widgetDict)
       
        self.label = Tkinter.Label(self, **ldefaults)
        self.label.grid(row=0, column=0, sticky='w')
        self.widget = widgetName(self, **wdefaults)
        self.widget.grid(row=0, column=1, sticky='e')

########
if __name__ == '__main__':
    root = Tkinter.Tk()
    widgetList = (
        [Tkinter.Entry,
         {'text':'An entryfield label:'},{}],
        [Tkinter.Button,
         {'text':'A button label:', 'bg':'peachpuff'},
         {'text':"I'm a button"}],
        [Tkinter.Label,
         {'text':'A label label:'}, {'text':"I'm a label", 'fg':'honeydew'}],
    )
    # for testing.
    def doit(widgetlist, part, method, **dict):
        for w in widgetlist:
            object = getattr(w, part, None)
            if object:
                command = getattr(object, method, None)
                if callable(command):
                    command(**dict)

    r = 0
    widgets=[]
    for name, ld, wd in widgetList:
        w = LabelledWidget(root, name, ld, wd)
        widgets.append(w)
        w.grid(row=r, col=0, sticky='ew')
        r += 1

    r = 0
    for w in widgets:
        w.grid(row=r, col=0)
        r += 1

    cmdList = (
        ['pink label', 'label', 'configure', {'fg':'pink'}],
        ['yellow widget', 'widget', 'configure', {'bg':'yellow'}],
        )

    c = 0
    for txt, part, method, dict in cmdList:
        button = Tkinter.Button(root, text=txt,
                                command=lambda w=widgets,
                                p=part, m=method, d=dict :
                                doit(w, p, m, **d))
        button.grid(row=r, col=c, sticky='w')
        c += 1
    button = Tkinter.Button(root, text='Exit', command=root.destroy)
    button.grid(row=r, col=c)
    
    root.mainloop()
--------------------------------------

Laura Creighton




More information about the Python-list mailing list