Skip to content Skip to sidebar Skip to footer

How Can I Get Tk Buttons, Generated By A For Loop, To Pass Input To Their Command? (python)

I have a program which dynamically generates a GUI. I don't know how many buttons I will have, if any at all. The specific problem is something like this: for varname in self.file

Solution 1:

I have to admit -- this one has me a little bit stumped. Since you're pairing a Button with an Entry and stringvar, one workaround is to wrap those together in a class. (I could probably argue that this is a little more elegant anyway...)

import Tkinter as tk

classButtonEntry(tk.Frame):
    def__init__(self,master,ss):
        tk.Frame.__init__(self)
        self.var=tk.StringVar()
        self.var.set(ss)
        self.Button=tk.Button(self,text='Button',command=lambda :self.var.set("foo!"))
        self.Entry=tk.Entry(self,textvariable=self.var)
        self.Button.grid(row=0,column=0)
        self.Entry.grid(row=0,column=1)


classApp(tk.Frame):
    def__init__(self,master=None):
        tk.Frame.__init__(self,master)
        self.BEs=[]
        for i inrange(10):
            b=ButtonEntry(self,'Button %d'%i)
            b.grid(row=i,column=0)
            self.BEs.append(b)


if __name__ == '__main__':
    root=tk.Tk()
    f=App(root)
    f.grid(row=0,column=0)
    root.mainloop()

However, I would really love to know why the lambda behaves the way it does. I thought for sure what you had should work.

EDIT

I've tracked down the behavior of the lambda function. https://stackoverflow.com/a/10452819/748858 gives a great example of how to do this properly. The problem is that the variables in the lambda function are still bound to the scope where the lambda was declared. In order to disassociate them with that scope, you need to set them as a keyword argument to the function. Nice! I learned something new this morning.

Solution 2:

Generally, you would associate the button with the varname and StringVar() via a dictionary, the key being the button's id or number, pointing to whatever. Since you are using a StringVar I assume you are doing this with Tkinter. An simple example follows that passes the button's number to a function that accesses the dictionary.

from Tkinter import *
from functools import partial

classButtonsTest:
   def__init__(self):
      self.top = Tk()
      self.top.title('Buttons Test')
      self.top_frame = Frame(self.top, width =400, height=400)
      self.button_dic = {}
      self.buttons()
      self.top_frame.grid(row=0, column=1)

      Button(self.top_frame, text='Exit', 
              command=self.top.quit).grid(row=10,column=1, columnspan=5)

      self.top.mainloop()

   ##-------------------------------------------------------------------         defbuttons(self):
      b_row=1
      b_col=0for but_num inrange(1, 11):
         ## note that the correct "but_num" is stored
         self.button_dic[but_num] = "self.cb_button_%d()" % (but_num)
         b = Button(self.top_frame, text = str(but_num), 
                    command=partial(self.cb_handler, but_num))
         b.grid(row=b_row, column=b_col)

         b_col += 1if b_col > 4:
            b_col = 0
            b_row += 1##----------------------------------------------------------------defcb_button_1(self):
      print"push button 1 and this code is executed"##----------------------------------------------------------------defcb_button_2(self):
      print"push button 2 and this code is executed"##----------------------------------------------------------------defcb_button_3(self):
      print"push button 3 and this code is executed"##----------------------------------------------------------------defcb_handler( self, cb_number ):
      print"cb_handler", cb_number, self.button_dic[cb_number]                
      if cb_number < 4:
         exec(self.button_dic[cb_number])

##===================================================================
BT=ButtonsTest() 

Post a Comment for "How Can I Get Tk Buttons, Generated By A For Loop, To Pass Input To Their Command? (python)"