Widget Identity

Why is it so freaking hard to find simple examples of so much stuff in the Python version of tkinter!?

The web is full of folks who want to use a loop to produce a bunch of widgets, but then can’t figure out how to address them since they were not assigned variable names. There are several approaches to solve this conundrum. tkinter has a set of perfectly good tools to use – but just try and find simple, non-geeky @$%#%^ examples of how they work. So this rant and the little demo code below demonstrates:

grid_location(x,y)
grid_slaves(row, column)
using str() to grab a pathname – thanks Mr. Shipman at New Mexico Tech
nametowidget(widget pathname)
winfo_atom
winfo_atomname

Some combination of the above can almost certainly get you the information you need, and they are all simple to use:

# TEST AREA for Widget Identity
# (c) 2018 John A. Oakey
# permission given to use for non-commercial purposes
#  standard set up header code 2

from tkinter import *
root = Tk()
root.attributes('-fullscreen', True)
root.configure(background='SteelBlue4')
scrW = root.winfo_screenwidth()
scrH = root.winfo_screenheight()  
workwindow = str(1024) + "x" + str(768)+ "+" +str(int((scrW-1024)/2)) + "+" +str(int((scrH-768)/2))
top1 = Toplevel(root, bg="light blue")
top1.geometry(workwindow)
top1.title("Top 1 - Workwindow")
top1.attributes("-topmost", 1)  # make sure top1 is on top to start
root.update()                   # but don't leave it locked in place
top1.attributes("-topmost", 0)  # in case you use lower or lift
#exit button - note: uses grid
b3=Button(root, text="Egress", name="eb3", command=root.destroy)
b3.grid(row=0,column=0,ipadx=10, ipady=10, pady=5, padx=5, sticky = W+N)
#____________________________

# first let's make a bunch of unnamed label widgets and a text box for our observations
for i in range(1,5):
    for x in range(1,5):
        nextlabel = Label(top1, width=25, height=2, bg="linen")
        nextlabel.grid(column = i, row = x, padx=10, pady=10, ipadx=5, ipady=5)
        nextlabel.configure(text = top1.winfo_atomname(top1.winfo_atom(nextlabel, displayof=0), displayof=0))
tx1=Text(top1, width=90, height=20)
tx1.grid(column=1,row=6,columnspan=5, pady=20, padx=20)


def tline(line):
    tx1.insert(END, line)
    tx1.insert(END, "\n")


x,y=700,300  # some random pixel points in the grid to find
gtup = top1.grid_location(x,y)  # given pixel location, grid_location returns grid column and row
tline("These are the row and column integers: " + str(gtup) + "  *0 was not used")
top1_slave = top1.grid_slaves(gtup[0], gtup[1])  # given col and row, grid_slaves return tuple of widgit slaves
w_pathname=str(top1_slave[0])  # only one widget which will be [0] - holds pathname .!toplevel.!label15
tline("This is variable w_pathname which is our label pathname extracted: "+ w_pathname)
w_id=(root.nametowidget(w_pathname)) #  convert pathname to widget name with nametowidget function
tline("Using nametowidget we convert it to a widget name: "+ str(w_id))              #  will look the same in print but it is not - can't substitute
tline("It looks the same printed but internally it is not.")
tline("Changing our target widget bg color to prove we have the goods.")
w_id.configure(bg="coral1") #  proof we can use it to affect a widget option attributes
# with name in variable w_id and pathname in variable w_pathname we can get id with winfo_atom
tline("The widget id integer is extracted to w_id with winfo_atom: " + str(w_id.winfo_atom(w_pathname,displayof=0)))
id_int = w_id.winfo_atom(w_pathname,displayof=0)
# and knowing the pathname and id integer we can come full circle and use it to find the widget name
w_name2=w_id.winfo_atomname(id_int, displayof=0)
tline("Using the name and atom we come full circle to geth the atomname: "+ str(w_name2))
tline("Are w_name2 and w_pathname the same?")
if w_name2==w_pathname:
    tline("w_name2 and w_pathname are the same")
else:
    tline("not so much")
tline("Are w_name2 and w_id the same?")
if w_name2==w_id:
    tline("w_name2 and w_id are the same")
else:
    tline("not so much")
   
#____________________________
root.mainloop()