Tkinter Button command query

Peter Otten __peter__ at web.de
Mon Apr 19 10:07:20 EDT 2004


Paul A. Wilson wrote:

> I'm new to Tkinter programming and am having trouble creating a
> reusable button bar... I want to be able to feed my class a dictionary
> of button names and function names, which the class will make.
> 
> My button bar is implemented a Frame subclass, which takes the button
> dictionary as an argument and displays the buttons on the screen:
> 
> class OptionsBar(Frame):
>    def __init__(self, buttonDict, parent=None)
>       Frame.__init__(self, parent)
>       parent.someFunction()    # This works fine
>       for (name, command) in buttonDict.items():
>          Button(self, text=name, command=command).pack(side=TOP,
> fill=BOTH)
> 
> and then another Frame subclass, e.g. MyWindow, uses the bar as
> follows:
> 
>    self.buttonDict = {'Button1':'someFunction',
>                       'Button2':'otherFunction'}
>    ...
>    myBar = OptionsBar(parent=self, buttonDict=self.buttonDict)
>    myBar.pack(side=RIGHT)
>    ...
> 
>    def someFunction():
>      do button stuff
> 
> My problem is that the Button instances aren't calling the correct
> functions when pressed. Is there anyway I get Button to call its
> parent frame's parent frame's functions? I've tried using
> 
>    self.buttonDict = {'Button1':'parent.someFunction',
>                       'Button2':'parent.otherFunction'}
> 
> but to no avail. Hope my explanations make sense.
> 
> Any suggestions?

Use the function identifier directly instead of a string to identify the
commands, e. g:

import Tkinter
class OptionsBar(Tkinter.Frame):
    def __init__(self, buttonDict, parent=None):
        Tkinter.Frame.__init__(self, parent)
        parent.someMethod()    # This works fine only if parent is not None
        for (name, command) in buttonDict.items():
            Tkinter.Button(self, text=name,
command=command).pack(side=Tkinter.TOP,
            fill=Tkinter.BOTH)

def aFunction():
    print "a function"

class MyWindow(Tkinter.Frame):
    def __init__(self, parent):
        Tkinter.Frame.__init__(self, parent)
        self.buttonDict = {'Button1': self.someMethod,
                          'Button2': aFunction}
        #...
        myBar = OptionsBar(parent=self, buttonDict=self.buttonDict)
        myBar.pack(side=Tkinter.RIGHT)
        #...

    def someMethod(self):
        print "some method"

root = Tkinter.Tk()
MyWindow(root).pack()
root.mainloop()

You can pass self.someMethod around as if it were a function. Python will
take care that the method is invoked with the instance denoted by self.

Note how I changed e. g. Button to Tkinter.Button. As you are already
creating reusable components you should also start to care about namespace
cluttering. If you are too lazy to type Tkinter in full beauty, use an
alias

import Tkinter as tk

and then tk.Button() etc.


Peter

PS: Do us - and yourself - the favour of using *4*-space indents. The more
people use it as a standard, the better you can tuck pieces of code from
different sources together.




More information about the Python-list mailing list