sidnical
sidnical

Reputation: 459

How to get widget name in event?

from tkinter import *

main = Tk()

def flipper(event):
    # I'd like to do this:
    #if widgetname == switcher:
        #do stuff
    #if widgetname == switcher1:
        #do stuff
    return

switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)


switcher1 = Label(main, bg='white', text="click here", font="-weight bold")
switcher1.grid()
switcher1.bind("<Button-1>", flipper)

switcher2 = Label(main, bg='white', text="click here", font="-weight bold")
switcher2.grid()
switcher2.bind("<Button-1>", flipper)

switcher3 = Label(main, bg='white', text="click here", font="-weight bold")
switcher3.grid()
switcher3.bind("<Button-1>", flipper)

switcher4 = Label(main, bg='white', text="click here", font="-weight bold")
switcher4.grid()
switcher4.bind("<Button-1>", flipper)

switcher5 = Label(main, bg='white', text="click here", font="-weight bold")
switcher5.grid()
switcher5.bind("<Button-1>", flipper)


main.mainloop()

In my event function I'd like to do different things based on the label that is clicked. What im stumped on is that I can only get the identifier number of the widget that is clicked, not the name. If I could get the identifier of all my widgets then I could do:

def flipper(event):
    if event.widget == switcher.identifier():
           do stuff

but I can't find how to get the id of a specified widget either...

How can I get the name of a widget by its identifier (event.widget())?

Or how can I get the identifier of a specified widget name?

If neither are possible, then I'd have to make a different function and bind for each label which is a lot of work that hopefully is not necessary.


Edit:

from tkinter import *

main = Tk()

def flipper(event, switch):
    if switch.widget == 's1':
        print("got it")

switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)
switcher.widget = 's1'


main.mainloop()

Upvotes: 9

Views: 24488

Answers (5)

David Myers
David Myers

Reputation: 31

I had the same issue I found easy way was to use bind method. apparent name property is private but can be accessed via _name This is useful if you plan to generate widgets dynamically at runtime

# Import Module
from tkinter import *
 
# create root window
root = Tk()
 
# root window title and dimension
root.title("Welcome to Test window")
# Set geometry (widthxheight)
root.geometry('350x200')

#adding a label to the root window
lbl = Label(root, text = "Press a button")
lbl.grid()

#define mouse up event
def mous_up(ev:Event):
    #get calling widget from event
    sender:Button = ev.widget
    
    #set label text
    lbl.configure(text = sender._name + "  up")
    
    #read foreground color from button 
    #If red make green, else make red
    if sender.cget('fg') == "red":
        #normal color
        sender.configure(fg='lime')
        #mouse over color
        sender.configure(activeforeground='green')
    else:
        #normal color
        sender.configure(fg="red")
        #mouse over color
        sender.configure(activeforeground='darkred')

#define mouse down event
def mous_down(ev:Event):
    lbl.configure(text = str(ev.widget._name) + " down")
 
# button widget with red color text
# inside
btn = Button(root, text = "Click me" ,
             fg = "red",name = "button-A")

#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)

# set Button grid
btn.grid(column=0, row=1)

#Create another button
btn =  Button(root, text = "Click me2" ,
             fg = "red",name="button2")

#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)

#absolute placement of button instead of 
#using grid system
btn.place(x=50,y=100)
 
# all widgets will be here
# Execute Tkinter
root.mainloop()

Upvotes: 3

Alex
Alex

Reputation: 11

I know this is an old post, but I had the same problem and I thought I should share a solution in case anyone is interested. You can give your widget a name by creating a subclass of the widget. E.g. "Button" is a widget. You can make a child widget "MyButton" which inherits from button and then add an instance variable to it (e.g. name, uniqueID etc.)

Here is a code snippet

class MyButton(Button):
    def __init__(self, master = None, textVal = "", wName = ""):
        Button.__init__(self, master, text =  textVal)
        self.widgetID = wName #unique identifier for each button. 

When you want to create a new button widget, use b = MyButton(.....), instead of b = Button(.......)

This way, you have all the functionality of a button, plus the unique identifier.

Upvotes: 1

furas
furas

Reputation: 142651

You can use event.widget to get standard parameters from clicked widget

example:

import tkinter as tk

def callback(event):
    print(event.widget['text'])

main = tk.Tk()

switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)

main.mainloop()

You can assign own variables to widgets

switcher.extra = "Hello"

and then get it

event.widget.extra

example:

import tkinter as tk

def callback(event):
    print(event.widget['text'])
    print(event.widget.extra)

main = tk.Tk()

switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)
switcher.extra = "Hello"

main.mainloop()

You can use lambda to bind function with arguments

bind("<Button-1>", lambda event:callback(event, "Hello"))

example:

import tkinter as tk

def callback(event, extra):
    print(event.widget['text'])
    print(extra)

main = tk.Tk()

switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", lambda event:callback(event, "Hello"))

main.mainloop()

Upvotes: 7

Bryan Oakley
Bryan Oakley

Reputation: 385970

You can't get the variable name that the widget is assigned to, that would be relatively useless. A widget could be assigned to more than one variable, or none at all.

Getting the label text

You have access to the actual widget, and you can use that to get the text that is on the label. Your example shows that all labels are the same, so this might not be useful to you:

def flipper(event):
    print("label text:", event.widget.cget("text"))

Using a custom widget name

You can also give a widget a name. You can't get back precisely the name, but you can come very close. For example, if you create a label like this:

switcher = Label(main, name="switcher", bg='white', text="click here", font="-weight bold")

You can get the string representation of the widget by splitting on "." and taking the last value:

def flipper(event):
    print("widget name:", str(event.widget).split(".")[-1])

Passing a name via the binding

Finally, you can set up your bindings such that the name is sent to the function:

switcher.bind("<Button-1>", lambda event: flipper(event, "switcher"))
switcher1.bind("<Button-1>", lambda event: flipper(event, "switcher1"))

Upvotes: 24

user4322543
user4322543

Reputation:

Quick and dirty - you could have the function check a switcher attribute.

def flipper(event, switch):
    if switch.widget == 's1':
        do_stuff
        return stuff
    if switch.widget == 's2':
        do_stuff
        return stuff

switcher1.widget = 's1'
switcher2.widget = 's2'

Upvotes: -1

Related Questions