4

Using Tkinter, I have many buttons. I would like the same callback function to be triggered every time any of the buttons pressed. How can I find out which button was pressed ?

def call(p1):
    # Which Button was pressed?
    pass

for i in range (50):
    B1 = Button(master, text = '...', width = 2)
    B1.grid(row = i*20, column = 60)               
    B1.bind('<Button-1>',call)

    B2 = Button(master, text = '...', width = 2)
    B2.grid(row = i*20, column = 60)               
    B2.bind('<Button-1>',call)
user1530405
  • 447
  • 1
  • 8
  • 16

4 Answers4

11

Using a list to reference the dynamically created buttons and lambda to store a reference to the index of the button object. You can determine which button was clicked. In the below examples I use .cget("text") on the button object to demonstrate accessing the button widget.

import tkinter as tk

root = tk.Tk()
root.minsize(200, 200)

btn_list = [] # List to hold the button objects

def onClick(idx):
    print(idx) # Print the index value
    print(btn_list[idx].cget("text")) #Print the text for the selected button

for i in range(10):
    # Lambda command to hold reference to the index matched with range value
    b = tk.Button(root, text = 'Button #%s' % i, command = lambda idx = i: onClick(idx))
    b.grid(row = i, column = 0)

    btn_list.append(b) # Append the button to a list

root.mainloop()

Alternatively you can use bind and then access the widget from the event object generated.

import tkinter as tk

root = tk.Tk()
root.minsize(200, 200)

def onClick(event):
    btn = event.widget # event.widget is the widget that called the event
    print(btn.cget("text")) #Print the text for the selected button

for i in range(10):
    b = tk.Button(root, text = 'Button #%s' % i)
    b.grid(row = i, column = 0)
    # Bind to left click which generates an event object
    b.bind("<Button-1>", onClick)

root.mainloop()
Steven Summers
  • 5,079
  • 2
  • 20
  • 31
1
  1. @Steven Summers' first example seems most clear to me, but I think doing it without the list is even clearer.
  2. The way I understood the question, you not only want to know which button was clicked but you also want each button to call one other, undescribed function (universal in my example below). In that case, you can use the very handy combine_funcs (see: Have multiple commands when button is pressed) to call two functions from one widget.

Here is my code. Instead of a list, I simply have a string that is changed and printed with each click.

import tkinter as tk

root = tk.Tk()
root.minsize(200, 200)

buttonVal = ''                             

def combine_funcs(*funcs):
    def combined_func(*args, **kwargs):
        for f in funcs:
            f(*args, **kwargs)
    return combined_func

def universal():
    print 'Universal function is called'    

def button_check(buttonName):
    buttonVal = buttonName
    print buttonVal   # Or whatever you want to do with the button info

for i in range(10):
    B1 = tk.Button(root, text = 'Button #%s' % i, command = combine_funcs(universal, lambda buttonName = 'Button #%s' % i:button_check(buttonName)))
    B1.grid(row = i, column = 0)

root.mainloop()
Community
  • 1
  • 1
deppen8
  • 153
  • 12
0

Use lambda:

B1 = Button(master, text = '...', width = 2, command = lambda: call('B1') )

And so on...

Kenly
  • 24,317
  • 7
  • 44
  • 60
-1

This might not be the simplest solution, but it is the only one I could come up with.

from Tkinter import *
master = Tk()

L = []

def call(p1):
    for i in range(len(L)):
        if str(L[i]) == str(p1.widget):
            print 'Button' + str(i)
            break  

for i in range (50):
    exec("Button" + str(i) + " = Button(master, text = '...', width = 2)")
    exec("Button" + str(i) + ".grid(row = i*20, column = 60)")               
    exec("Button" + str(i) + ".bind('<Button-1>',call)")

    s = 'L.append(str(Button' + str(i) + '))'
    exec(s)
user1530405
  • 447
  • 1
  • 8
  • 16