ZackBoi
ZackBoi

Reputation: 341

Refer to tkinter widget by its instance

I am learning Python w/ Tkinter and I recently learned the difference between the reference and the name/instance of a widget. The reference is the string you assign to a widget (which can be changed later on), but the name seems to be the actual identity of the widget (which is immutable). Essentially it seems as though the reference is a nickname of a widget because it can change overtime and be different depending on who you are talking to, while the actual name of the widget on the widget's drivers license is always the same. Specifically, in this line of code...

sample_frame = Frame(root, name = 'frame1', bg = 'blue', height = 50, width = '50')

"sample frame" is the reference, while 'frame1' is the name.

Unless I specifically assign the string 'frame1' as the name of this frame, python automatically generates a number sequence as its name. In order to view the name of any widget you just have to add...

print(str(sample_frame))

(the output in this example is .frame1)

So in Tkinter if I wanted to place this frame in my GUI i would have to pack/grid/place it in the following line like so...

sample_frame.pack()

But what I would like to do is call the pack method on this frame widget by its name rather than its reference. Something like this...

frame1.pack() #or
.frame1.pack() #because of that period

The problem is that Python claims frame1 was never defined, and .frame1 is invalid syntax. Does anybody know how to do something like this? Thanks.

For broader context I am doing this because I iterated the creation of 21 different frames and placed them in a 3x7 grid. Because of this all 21 frames have an identical reference. BUT, I made sure to make the name of each frame corresponds with its position.

Upvotes: 2

Views: 2928

Answers (2)

fhdrsdg
fhdrsdg

Reputation: 10532

While I fully agree with jasonharper's answer that you should keep a proper reference to the widgets and I do not recommend using what I'm about to explain, there actually is a way to achieve what you're asking. There's a widget method called nametowidget(), which returns the widget object when you give it a name. Note that you should call the method on the object (Tk, Toplevel, Frame) that contains the widget you're looking for.

So following your example, this works:

from tkinter import *
root = Tk()
sample_frame = Frame(root, name = 'frame1', bg = 'blue', height = 50, width = '50')
root.nametowidget('frame1').pack()
root.mainloop()

And if you would do the same with a button inside the frame you should do:

sample_button = Button(sample_frame, text='Button', name='button1')
sample_frame.nametowidget('button1').pack()

Upvotes: 2

jasonharper
jasonharper

Reputation: 9597

The name= option sets the name of the widget within the Tcl environment that actually implements the GUI - it has no effect on the Python side. The only reason I can think of for doing this is that it might make Tcl error messages somewhat easier to read (the auto-generated widget name that you'd otherwise get is not particularly meaningful).

As always, the proper way to deal with multiple objects created in a loop is to store them in a container of some sort. In your case, it could be a 21 element list, a nested list (widget[row][column]), or perhaps a dict indexed by tuples (widget[row, column]).

Upvotes: 4

Related Questions