How to get a widget name with tkinter's nametowidget function within a Class
Question:
I’m writing a tkinter mini project within a class, and am currently trying to get the name of a button widget but I get a Traceback error every time the program I try to run the program. I was curious as to how to go about fixing the nametowidget line to get the proper name of the widget.
from tkinter import *
import tkinter.messagebox
root = Tk()
class WindowPane(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.master = master
self.WindowWidget()
def WindowWidget(self):
self.stringer = StringVar()
self.button1 = Button(text = "Click me")
self.button1.place(x=200,y=50)
print(self.master.nametowidget(".button1"))
root.geometry("200x200")
playback = WindowPane(root)
root.mainloop()
Answers:
The “name” in nametowidget
isn’t the name of the variable used to keep a reference to the widget (ie: in this example it’s not “button1”). This makes sense because you can have multiple variables all pointing to the same object – how would python know which name you want?
The name refers to the internal widget name used by the embedded tcl/tk interpreter. Normally this is computed based on the name of the parent, the widget class and an optional number. For example, the first frame you create by default will have the name .!frame
, the next frame will have the name .!frame2
, and so on. The first button inside the first frame will be named .!frame1.!button1
, etc.
You can see the name of any widget by printing out its string representation. For example, in your code, you could do print(str(self.button1)
which will show you that the name is actually .!button
You can’t use anything built into tkinter to convert a string like "button1"
to the actual widget. However, a variable such as self.button1
is an attribute of the current object, so you can use python’s built-in getattr
function to get the value of an attribute with a given name.
In your case you can use getattr(self, "button1")
to get a reference to the actual widget object.
Bryan Oakleys explanation did not work for me. Using dir
on a Frame
of f
revealed that after packing an Entry
e
object into the frame that it did not become an attribute of f
. Rather, it was a value of a dictionary f.children
where the key was the name of e
, !entry
.
Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter as tk
>>> f = tk.Frame()
>>> dir(f)
['_Misc__winfo_getint', '_Misc__winfo_parseitem', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bind', '_configure', '_displayof', '_do', '_getboolean', '_getconfigure', '_getconfigure1', '_getdoubles', '_getints', '_grid_configure', '_gridconvvalue', '_last_child_ids', '_name', '_nametowidget', '_noarg_', '_options', '_register', '_report_exception', '_root', '_setup', '_subst_format', '_subst_format_str', '_substitute', '_tclCommands', '_w', '_windowingsystem', 'after', 'after_cancel', 'after_idle', 'anchor', 'bbox', 'bell', 'bind', 'bind_all', 'bind_class', 'bindtags', 'cget', 'children', 'clipboard_append', 'clipboard_clear', 'clipboard_get', 'columnconfigure', 'config', 'configure', 'deletecommand', 'destroy', 'event_add', 'event_delete', 'event_generate', 'event_info', 'focus', 'focus_displayof', 'focus_force', 'focus_get', 'focus_lastfor', 'focus_set', 'forget', 'getboolean', 'getdouble', 'getint', 'getvar', 'grab_current', 'grab_release', 'grab_set', 'grab_set_global', 'grab_status', 'grid', 'grid_anchor', 'grid_bbox', 'grid_columnconfigure', 'grid_configure', 'grid_forget', 'grid_info', 'grid_location', 'grid_propagate', 'grid_remove', 'grid_rowconfigure', 'grid_size', 'grid_slaves', 'image_names', 'image_types', 'info', 'keys', 'lift', 'location', 'lower', 'mainloop', 'master', 'nametowidget', 'option_add', 'option_clear', 'option_get', 'option_readfile', 'pack', 'pack_configure', 'pack_forget', 'pack_info', 'pack_propagate', 'pack_slaves', 'place', 'place_configure', 'place_forget', 'place_info', 'place_slaves', 'propagate', 'quit', 'register', 'rowconfigure', 'selection_clear', 'selection_get', 'selection_handle', 'selection_own', 'selection_own_get', 'send', 'setvar', 'size', 'slaves', 'tk', 'tk_bisque', 'tk_focusFollowsMouse', 'tk_focusNext', 'tk_focusPrev', 'tk_setPalette', 'tk_strictMotif', 'tkraise', 'unbind', 'unbind_all', 'unbind_class', 'update', 'update_idletasks', 'wait_variable', 'wait_visibility', 'wait_window', 'waitvar', 'widgetName', 'winfo_atom', 'winfo_atomname', 'winfo_cells', 'winfo_children', 'winfo_class', 'winfo_colormapfull', 'winfo_containing', 'winfo_depth', 'winfo_exists', 'winfo_fpixels', 'winfo_geometry', 'winfo_height', 'winfo_id', 'winfo_interps', 'winfo_ismapped', 'winfo_manager', 'winfo_name', 'winfo_parent', 'winfo_pathname', 'winfo_pixels', 'winfo_pointerx', 'winfo_pointerxy', 'winfo_pointery', 'winfo_reqheight', 'winfo_reqwidth', 'winfo_rgb', 'winfo_rootx', 'winfo_rooty', 'winfo_screen', 'winfo_screencells', 'winfo_screendepth', 'winfo_screenheight', 'winfo_screenmmheight', 'winfo_screenmmwidth', 'winfo_screenvisual', 'winfo_screenwidth', 'winfo_server', 'winfo_toplevel', 'winfo_viewable', 'winfo_visual', 'winfo_visualid', 'winfo_visualsavailable', 'winfo_vrootheight', 'winfo_vrootwidth', 'winfo_vrootx', 'winfo_vrooty', 'winfo_width', 'winfo_x', 'winfo_y']
>>> f.children
{}
>>> e = tk.Entry(f)
>>> f.children
{'!entry': <tkinter.Entry object .!frame.!entry>}
>>> getattr(f, 'entry')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Frame' object has no attribute 'entry'
>>> getattr(f, '!entry')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Frame' object has no attribute '!entry'
>>>```
I’m writing a tkinter mini project within a class, and am currently trying to get the name of a button widget but I get a Traceback error every time the program I try to run the program. I was curious as to how to go about fixing the nametowidget line to get the proper name of the widget.
from tkinter import *
import tkinter.messagebox
root = Tk()
class WindowPane(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.master = master
self.WindowWidget()
def WindowWidget(self):
self.stringer = StringVar()
self.button1 = Button(text = "Click me")
self.button1.place(x=200,y=50)
print(self.master.nametowidget(".button1"))
root.geometry("200x200")
playback = WindowPane(root)
root.mainloop()
The “name” in nametowidget
isn’t the name of the variable used to keep a reference to the widget (ie: in this example it’s not “button1”). This makes sense because you can have multiple variables all pointing to the same object – how would python know which name you want?
The name refers to the internal widget name used by the embedded tcl/tk interpreter. Normally this is computed based on the name of the parent, the widget class and an optional number. For example, the first frame you create by default will have the name .!frame
, the next frame will have the name .!frame2
, and so on. The first button inside the first frame will be named .!frame1.!button1
, etc.
You can see the name of any widget by printing out its string representation. For example, in your code, you could do print(str(self.button1)
which will show you that the name is actually .!button
You can’t use anything built into tkinter to convert a string like "button1"
to the actual widget. However, a variable such as self.button1
is an attribute of the current object, so you can use python’s built-in getattr
function to get the value of an attribute with a given name.
In your case you can use getattr(self, "button1")
to get a reference to the actual widget object.
Bryan Oakleys explanation did not work for me. Using dir
on a Frame
of f
revealed that after packing an Entry
e
object into the frame that it did not become an attribute of f
. Rather, it was a value of a dictionary f.children
where the key was the name of e
, !entry
.
Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter as tk
>>> f = tk.Frame()
>>> dir(f)
['_Misc__winfo_getint', '_Misc__winfo_parseitem', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bind', '_configure', '_displayof', '_do', '_getboolean', '_getconfigure', '_getconfigure1', '_getdoubles', '_getints', '_grid_configure', '_gridconvvalue', '_last_child_ids', '_name', '_nametowidget', '_noarg_', '_options', '_register', '_report_exception', '_root', '_setup', '_subst_format', '_subst_format_str', '_substitute', '_tclCommands', '_w', '_windowingsystem', 'after', 'after_cancel', 'after_idle', 'anchor', 'bbox', 'bell', 'bind', 'bind_all', 'bind_class', 'bindtags', 'cget', 'children', 'clipboard_append', 'clipboard_clear', 'clipboard_get', 'columnconfigure', 'config', 'configure', 'deletecommand', 'destroy', 'event_add', 'event_delete', 'event_generate', 'event_info', 'focus', 'focus_displayof', 'focus_force', 'focus_get', 'focus_lastfor', 'focus_set', 'forget', 'getboolean', 'getdouble', 'getint', 'getvar', 'grab_current', 'grab_release', 'grab_set', 'grab_set_global', 'grab_status', 'grid', 'grid_anchor', 'grid_bbox', 'grid_columnconfigure', 'grid_configure', 'grid_forget', 'grid_info', 'grid_location', 'grid_propagate', 'grid_remove', 'grid_rowconfigure', 'grid_size', 'grid_slaves', 'image_names', 'image_types', 'info', 'keys', 'lift', 'location', 'lower', 'mainloop', 'master', 'nametowidget', 'option_add', 'option_clear', 'option_get', 'option_readfile', 'pack', 'pack_configure', 'pack_forget', 'pack_info', 'pack_propagate', 'pack_slaves', 'place', 'place_configure', 'place_forget', 'place_info', 'place_slaves', 'propagate', 'quit', 'register', 'rowconfigure', 'selection_clear', 'selection_get', 'selection_handle', 'selection_own', 'selection_own_get', 'send', 'setvar', 'size', 'slaves', 'tk', 'tk_bisque', 'tk_focusFollowsMouse', 'tk_focusNext', 'tk_focusPrev', 'tk_setPalette', 'tk_strictMotif', 'tkraise', 'unbind', 'unbind_all', 'unbind_class', 'update', 'update_idletasks', 'wait_variable', 'wait_visibility', 'wait_window', 'waitvar', 'widgetName', 'winfo_atom', 'winfo_atomname', 'winfo_cells', 'winfo_children', 'winfo_class', 'winfo_colormapfull', 'winfo_containing', 'winfo_depth', 'winfo_exists', 'winfo_fpixels', 'winfo_geometry', 'winfo_height', 'winfo_id', 'winfo_interps', 'winfo_ismapped', 'winfo_manager', 'winfo_name', 'winfo_parent', 'winfo_pathname', 'winfo_pixels', 'winfo_pointerx', 'winfo_pointerxy', 'winfo_pointery', 'winfo_reqheight', 'winfo_reqwidth', 'winfo_rgb', 'winfo_rootx', 'winfo_rooty', 'winfo_screen', 'winfo_screencells', 'winfo_screendepth', 'winfo_screenheight', 'winfo_screenmmheight', 'winfo_screenmmwidth', 'winfo_screenvisual', 'winfo_screenwidth', 'winfo_server', 'winfo_toplevel', 'winfo_viewable', 'winfo_visual', 'winfo_visualid', 'winfo_visualsavailable', 'winfo_vrootheight', 'winfo_vrootwidth', 'winfo_vrootx', 'winfo_vrooty', 'winfo_width', 'winfo_x', 'winfo_y']
>>> f.children
{}
>>> e = tk.Entry(f)
>>> f.children
{'!entry': <tkinter.Entry object .!frame.!entry>}
>>> getattr(f, 'entry')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Frame' object has no attribute 'entry'
>>> getattr(f, '!entry')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Frame' object has no attribute '!entry'
>>>```