Reputation: 1025
I am creating a card game in tkinter and need help with referencing to the frame names. My problem is that when I want to "refresh" the frame, I need to destroy and recreate it and this changes the progressive numbering of the frames.
Please take a look at the code below. The example shows that the third frame every time gets a new name as it gets recreated.
import tkinter as tk
class RootFrame(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.main_window = tk.Frame(self)
self.main_window.pack(side="top", fill="both", expand=True)
self.main_label = tk.Label(self.main_window, text="Main Window")
self.main_label.pack()
self.second_frame = SecondFrame(self.main_window, self)
self.second_frame.pack()
class SecondFrame(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
super().__init__(*args, **kwargs)
self.controller = controller
label = tk.Label(self, text="Second Frame")
label.pack()
self.create_third_frame()
def create_third_frame(self):
self.third_frame = ThirdFrame(self, self.controller)
self.third_frame.pack()
def update_frame(self):
self.third_frame.destroy()
self.create_third_frame()
class ThirdFrame(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
super().__init__(*args, **kwargs)
self.controller = controller
self.parent = parent
label = tk.Label(self, text="Third Frame")
label.pack()
refresh_button = tk.Button(
self, text="Resfresh", command=self.parent.update_frame)
refresh_button.pack()
print(self.winfo_name())
if __name__ == "__main__":
app = RootFrame()
app.mainloop()
The code above is used to illustrate the problem. Please run the code and you'll see the changing widget name in the terminal.
I use winfo_parent
and winfo_name
in my actual code to create different conditions for button bindings. For example, if the user clicks a widget1
in frame6
happens X and when I click a widget8
in frame2
happens Y. This works until I destroy()
and recreate something and everything breaks.
I suppose that using winfo_name
and winfo_parent
for this kind of referencing is not the correct way to get around, but I really can't think of anything else.
Upvotes: 0
Views: 2861
Reputation: 13888
I'm not sure exactly what you are asking, but you can assign a specific name to the widget:
def create_third_frame(self):
self.third_frame = ThirdFrame(self, self.controller, name='testframe')
self.third_frame.pack()
Then each time the name of the frame created will be consistent.
You can also reference the widget by name with Tk().nametowidget()
, see this relevant answer here: Is it possible to search widget by name in Tkinter?
>>> from Tkinter import * >>> win = Tk() >>> button = Button( Frame( win, name = "myframe" ), name = "mybutton" ) >>> win.nametowidget("myframe.mybutton") <Tkinter.Button instance at 0x2550c68>
I would recommend sticking with a OOP approach however, and just reference it with from your code like self.thirdframes
where you might have a list
or dict
of ThirdFrame
objects. This way your python code can easily reference the objects without going back to the tcl interpreter and parse the widget name. If you ever will only have one ThirdFrame
, then just reference back to self.thirdframe
whenever you need it.
Upvotes: 1