0

I am trying to use lambda to create callbacks for tkinter buttons.

There are multiple buttons and each callback needs to pass an object inside it. Following code is what I am doing and is running fine

var0 = tk.StringVar()    

label = tk.Label(top, bg = "White",height = 2, width = 12,textvariable=var0, justify="right")
def b0Callback(var):
  var.set(var.get()+"0")
return
# creating a label which will print value of the any of the 0-9 button pressed 

# creating a button 0 
b0 = tk.Button(numFrame0, height = 1, width = 4, bg = "grey", text = 
"0",command =  lambda: b0Callback(var0))

 #there are more buttons like that

var0 is used to update a label. Above code is working fine but I have to create callback for 0 to 9 and I have to just repeat above definition. So I tried using following example from this tutorial

def myfunc(n):
 return lambda a : a * n

mydoubler = myfunc(2)
mytripler = myfunc(3)

print(mydoubler(11)) 
print(mytripler(11))

Using it I did following

def Callback(n):
 return lambda var.set(var.get()+n)

b0Callback = Callback("0")

This shows error invalid index in the return line at var.set

Is there any way to pass var0 in this case to avoid this error?

Tabi
  • 1
  • 1

2 Answers2

0

I have now solved the problem, here is the final code:

I have also changed the number of buttons to 300 and added code to arrange them all in a nice grid, just for fun. (You can change this to however many you want by changing for number in range(1, whatever).

import tkinter as tk


class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.var0 = tk.StringVar()
        self.var0.set('0')

        # creating buttons and adding them to dictionary
        self.buttons = {}
        for number in range(1, 301):
            self.buttons.update({'button' + str(number): tk.Button(self, height=1, width=4, bg="grey", text=number)})

        label = tk.Label(self, textvariable=self.var0, font='none 50')
        label.grid(column=0, row=0)

        for button in self.buttons:
            self.buttons[button].bind('<Button-1>', lambda event, num=button[6:]: self.Callback(event, num))

            self.buttons[button].grid(column=(int(button[6:]) % 10), row=(int(button[6:]) / 10) + 1)

    def Callback(self, event, num):
        self.var0.set(num)
        self.update()
hegash
  • 833
  • 1
  • 7
  • 16
  • Sorry for ambiguity, I updated question. I am using var0 to update value on a label and there are 10 buttons each has 0-9 digit on it. Whatever button is pressed value will be updated on label – Tabi Jan 05 '19 at 11:16
0

Maybe its only me, but I don't see a reason for using lambda if you just want to add a number to the label text.

Lets make a function for it that gets your StringVar() as a variable and adds some number to it:

def button_callback(str_var, number):
    str_var.set(str_var.get() + str(number))

To run this command we simply put it in the code as a lambda function, otherwise it will run upon initialization (because we are providing a function instead of a reference).

So to run it within a button we declare it like this:

my_button = Button(root, text='Some text here', command=lambda: button_callback(my_string_var, 5))

The '5' could be potentially changed to any other number.

Emanuel L
  • 101
  • 8
  • It works in this way too but on first run the callbacks are getting called and printing all the values so I had to use lambda. Solution I got from [here](https://stackoverflow.com/questions/6920302/how-to-pass-arguments-to-a-button-command-in-tkinter) – Tabi Jan 05 '19 at 11:18
  • That is correct. I added a brief explanation and an example on how to use it. – Emanuel L Jan 05 '19 at 14:33