Tkinter Button command query

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Paul A. Wilson

    Tkinter Button command query

    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(Fram e):
    def __init__(self, buttonDict, parent=None)
    Frame.__init__( self, parent)
    parent.someFunc tion() # This works fine
    for (name, command) in buttonDict.item s():
    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':'som eFunction',
    'Button2':'othe rFunction'}
    ...
    myBar = OptionsBar(pare nt=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':'par ent.someFunctio n',
    'Button2':'pare nt.otherFunctio n'}

    but to no avail. Hope my explanations make sense.

    Any suggestions?

    Cheers
    PAW
  • Peter Otten

    #2
    Re: Tkinter Button command query

    Paul A. Wilson wrote:
    [color=blue]
    > 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(Fram e):
    > def __init__(self, buttonDict, parent=None)
    > Frame.__init__( self, parent)
    > parent.someFunc tion() # This works fine
    > for (name, command) in buttonDict.item s():
    > 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':'som eFunction',
    > 'Button2':'othe rFunction'}
    > ...
    > myBar = OptionsBar(pare nt=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':'par ent.someFunctio n',
    > 'Button2':'pare nt.otherFunctio n'}
    >
    > but to no avail. Hope my explanations make sense.
    >
    > Any suggestions?[/color]

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

    import Tkinter
    class OptionsBar(Tkin ter.Frame):
    def __init__(self, buttonDict, parent=None):
    Tkinter.Frame._ _init__(self, parent)
    parent.someMeth od() # This works fine only if parent is not None
    for (name, command) in buttonDict.item s():
    Tkinter.Button( self, text=name,
    command=command ).pack(side=Tki nter.TOP,
    fill=Tkinter.BO TH)

    def aFunction():
    print "a function"

    class MyWindow(Tkinte r.Frame):
    def __init__(self, parent):
    Tkinter.Frame._ _init__(self, parent)
    self.buttonDict = {'Button1': self.someMethod ,
    'Button2': aFunction}
    #...
    myBar = OptionsBar(pare nt=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.

    Comment

    • Fredrik Lundh

      #3
      Re: Tkinter Button command query

      Paul A. Wilson wrote:
      [color=blue]
      > 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(Fram e):
      > def __init__(self, buttonDict, parent=None)
      > Frame.__init__( self, parent)
      > parent.someFunc tion() # This works fine
      > for (name, command) in buttonDict.item s():
      > Button(self, text=name, command=command ).pack(side=TOP ,
      > fill=BOTH)[/color]

      Tkinter wants the functions, not the names of the functions. you can use
      getattr() to get around this:

      for (name, command) in buttonDict.item s():
      command = getattr(parent, command)
      Button(self, text=name, command=command )...

      (getattr(obj, "name") is the same as obj.name)

      </F>




      Comment

      Working...