5

I'm trying to create a list of buttons that are clicked with this lambda function:

button1.config(command=(lambda x: (clicked.append(x)))(button1.cget("text")))

It seems to sort of work but it prints the button text immediately i.e. it doesn't wait for user to click the button.

Any ideas on how to make it responsive to the button click?

class GraphicsInterface:

    def __init__(self):
        self.window = Tk()
        self.window.geometry("720x500")

        clicked=[]
        button1 = Button(self.window, text="Dice 1", width=13)
        button1.place(x=60, y=160)

        button1.config(command=(lambda x: (clicked.append(x)))(button1.cget("text")))

        print(clicked)
Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124

2 Answers2

3

Trying to do all this in a lambda is the wrong approach. It's simply too confusing, if not impossible to do what you want. Instead, create a method that does the work, and use lambda only as a way to call that function:

from Tkinter import *
class GraphicsInterface:

    def __init__(self):
        self.window = Tk()
        self.window.geometry("720x500")

        self.clicked=[]
        button1 = Button(self.window, text="Dice 1", width=13)
        button2 = Button(self.window, text="Dice 2", width=13)
        button1.pack()
        button2.pack()

        button1.configure(command=lambda btn=button1: self.OnClick(btn))
        button2.configure(command=lambda btn=button2: self.OnClick(btn))

        self.window.mainloop()

    def OnClick(self, btn):
        text = btn.cget("text")
        self.clicked.append(text)
        print "clicked:", self.clicked

app = GraphicsInterface()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Ah, yes works perfectly. However, can you explain why lambda is necessary? For example, I tried button1.configure(command=self.OnClick(button1)) which resulted in the same problem as before. Why does it call the function here before the user clicks? Also, I'm not super familiar with lambda in general...can you explain the syntax of "lambda btn=button1" in particular? –  Jun 01 '11 at 18:53
  • @sq1020: lamda is necessary because without it, or something like `functools.partial`, there is no way to pass arguments to the callback. This is because the `command` option must be given a reference to a function. `lambda` conveniently returns a handle to an anonymous function. When you do `command=self.OnClick(button1)` you are asking python to run the command `self.OnClick(button1)` and use the result of that as the value of the `command` attribute. – Bryan Oakley Jun 01 '11 at 19:10
2

One way would be to bind the button click event to a function which appends the text to your clicked list. For example,

    self.clicked=[]

    self.button1 = Button(self.window, text="Dice 1", width=13)
    self.button1.place(x=60, y=160)
    self.button1.bind("<Button-1>",self.callback)


def callback(self,event):
    self.clicked.append(event.widget.cget("text"))

You could then add other buttons that also call callback, and get their text through the event parameter.

Stephen Terry
  • 6,169
  • 1
  • 28
  • 31
  • This has the downside of not working if you use the keyboard to invoke the button (use tab to move focus to a button, then press the space bar). – Bryan Oakley Jun 01 '11 at 17:47