Python Forum
[Tkinter] Button click problem using OOP
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Button click problem using OOP
Can anyone help me with a problem illustrated in the code below. I am instantiating three tkinter buttons and saving the objects in a list which is I think a fairly standard way of doing things. The buttons can then be managed, colour change, text etc by referencing them via their index in the list. But if a button is clicked it seems impossible to detect which button it was. The only button object that is "active", if you want to call it that, is the last one that was instantiated in the For loop. Which ever button is clicked, it is that object that handles the click event. Is there a way of detecting which button is clicked when they have been instantiated this way. Thank you for sharing your expertise.


import tkinter as tk

class Butman(tk.Frame):
    def __init__(self,MyNumber):
        self.MyNumber = MyNumber
    def SetCol(self,col):
        self.but.config(bg = col)
    def SetText(self,Text):
        self.but.config(text = Text)

def DoSomething():
    print ("something done")
frame2 = tk.Frame(bg="grey", height = 720 ,width = 1280)
ButObj = []
for x in range(0,3):
    B = Butman(x)
    B.but=tk.Button(frame2, state="normal", text="sometext",compound= tk.CENTER,font=('comicsans', 
    16),relief=tk.FLAT,command = lambda: DoSomething()), rely=x/4, relwidth=0.18, relheight=0.18)
Why not pass the button as an argument to the function?
import tkinter as tk
root = tk.Tk()

def button_pressed(button):
frame = tk.Frame()

b1 = tk.Button(frame, text='Hello')
b1.configure(command = lambda b = b1: button_pressed(b))
b1.grid(row=0, column=0)

b2 = tk.Button(frame, text='Goodbye')
b2.configure(command = lambda b = b2: button_pressed(b))
b2.grid(row=1, column=0)

label = tk.Label(frame, text = 'Button Text')
label.grid(row=2, column=0)
I think you kind of over thought it, the class isn't needed
Quote: Is there a way of detecting which button is clicked when they have been instantiated this way.
Yes by indexing a list and using functool -> partial.
here's an example:
import tkinter as tk
from functools import partial

root= tk.Tk()

def do_something(index):

frame= tk.Frame(bg='gray60', width= 1280, height= 720)
button_list= []
for x in range(0,3):
    text_='Button {0}'.format(x)
                       command= partial(do_something,x),
                       relief= tk.FLAT))
    button_list[-1].place(relx=x/4, rely=x/4, relwidth=0.18, relheight=0.18)

Gribouillis likes this post
Thank you for your replies. I have learnt something from both of them.
I could pass the button as an argument as you suggest deanhistad but I need to configure up to 20 buttons, so I would prefer them to be configured in a loop.

Which using partial functions does. I've never come across partial functions or the Functools module before. Having researched it a bit I can see you need to generate a new function of the partial function, and call the new function supplying any if needed additional arguments. Can't quite see how a new function of the partial(do_something,x) is made/called when a button is clicked.
Another puzzle your solution has produced is why command = lambda:do_something(x) does not work. Why do you need to use a partial function. You would think that x, the list index basically, would be passed to the do_something function and the correct button would be actioned. What happens is the same as the Class scenario where the last button made is always actioned which ever button is clicked.

Anyway, having got all that clear in my mind, it's great when solutions provide more questions, that's how we learn.
command = lambda:do_something(x) does not work because lambdas are evaluated when called. IN this example I make three buttons and all are set to call DoSomething and passing the argument I.
import tkinter as tk

buttons = []

def DoSomething(args):

root = tk.Tk()
f = tk.Frame()

for i in range(3):
    b = tk.Button(f, command = lambda : DoSomething(i), text=str(i))
    b.grid(row=0, column=i)
When I press any button the program prints "2". Why is that?

How about answer this. What is the value of i? In my Python console I type i and it responds "2". I press a button, the button executes the lambda. The lambda calls DoSomething and passes the value of i.

To lock in the "i" argument in the callback you can use a partial function. The partial function arguments are frozen when the partial function is created. You are not actually setting the "command" to DoSomething(i), you are setting it to DoSomething(0) or DoSomething(1). You can do something similar with a lambda.
import tkinter as tk

buttons = []

def DoSomething(args):

root = tk.Tk()
f = tk.Frame()

for i in range(3):
    b = tk.Button(f, command = lambda x = i: DoSomething(x), text=str(i))
    b.grid(row=0, column=i)
Thanks for the great explanation deanhystad. Yes I asked the console to print i, and yes it equalled 2. I like the lambda solution, giving arguments before the colon which are evaluated at run rather than at execution. In fact this is a solution to my first post where I make objects of the buttons.

All's good Thanks

Possibly Related Threads…
Thread Author Replies Views Last Post
  Figure Gets Larger Every time I click a show button joshuagreineder 2 1,006 Aug-11-2022, 06:25 AM
Last Post: chinky
  problem with radio button crook79 3 3,248 Aug-12-2021, 02:30 PM
Last Post: deanhystad
  [Tkinter] Modify Class on Button Click KDog 4 3,674 May-11-2021, 08:43 PM
Last Post: KDog
  tkinter python button position problem Nick_tkinter 3 3,109 Jan-31-2021, 05:15 AM
Last Post: deanhystad
  tkinter | Button color text on Click Maryan 2 3,119 Oct-09-2020, 08:56 PM
Last Post: Maryan
  Closing window on button click not working kenwatts275 4 3,282 May-03-2020, 01:59 PM
Last Post: deanhystad
  Problem about image and button scotesse 5 2,636 Apr-27-2020, 10:09 AM
Last Post: scotesse
  Problem with Submit button Tkinter Reldaing 2 3,409 Jan-05-2020, 01:58 AM
Last Post: balenaucigasa
  [Tkinter] Checking button click in Tkinter GalaxyCoyote 3 6,986 Oct-20-2019, 03:28 AM
Last Post: GalaxyCoyote
  [PyQt] Problem how to click a button inside a group box? mart79 2 3,052 Aug-05-2019, 01:21 PM
Last Post: mart79

Forum Jump:

User Panel Messages

Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020