Reputation: 21
I am trying to make two different screens and link them with each other using a button on each screen assigned respected functions to them as command.
Please help me to know why I get the following error :
bad window path name ".!frame"
when I press a button in the following code.
from tkinter import *
root = Tk()
my_height = 600
my_width = 350
root.geometry(f"{my_height}x{my_width}")
# root.maxsize(my_height, my_width)
# FRAMES
main_frame = Frame(root, bg="Red", borderwidth=30)
other_frame = Frame(root, bg="Yellow", borderwidth=30)
# first window
def main_screen():
other_frame.destroy()
Label(main_frame, text="First Window").pack()
Button(main_frame, text="GO", command=second_screen).pack()
main_frame.pack()
def second_screen():
main_frame.destroy()
Label(other_frame, text="Second Window").pack()
Button(other_frame, text="BACK", command=main_screen).pack()
other_frame.pack()
main_screen()
root.mainloop()
Upvotes: 2
Views: 153
Reputation: 2270
The problem is you delete the frame other_frame
before when you write other_frame.destroy()
. This makes it inaccessible by the rest of the program since you destroyed it.
So there would be two solutions: One would be to, as BryanOakley mentioned, to use .pack()
. The other would be to use .place()
.
.pack()
:from tkinter import *
root = Tk()
my_height = 600
my_width = 350
root.geometry(f"{my_height}x{my_width}")
# root.maxsize(my_height, my_width)
def main_screen():
other_frame.pack_forget()
main_frame.pack()
def second_screen():
main_frame.pack_forget()
other_frame.pack()
# FRAMES
main_frame = Frame(root, bg="Red", borderwidth=30)
other_frame = Frame(root, bg="Yellow", borderwidth=30)
Label(other_frame, text="Second Window").pack()
Button(other_frame, text="BACK", command=main_screen).pack()
Label(main_frame, text="First Window").pack()
Button(main_frame, text="GO", command=second_screen).pack()
# first window
main_screen()
root.mainloop()
.place()
:from tkinter import *
root = Tk()
my_height = 600
my_width = 350
root.geometry(f"{my_height}x{my_width}")
# root.maxsize(my_height, my_width)
# first window
def main_screen():
main_frame.place(relx = 0.5, rely = 0.1, anchor = "center")
other_frame.place(relx = 1.5, rely = 0.1, anchor = "center")
main_frame.update()
other_frame.update()
def second_screen():
main_frame.place(relx = -0.5, rely = 0.1, anchor = "center")
main_frame.update()
other_frame.place(relx = 0.5, rely = 0.1, anchor = "center")
other_frame.update()
# FRAMES
main_frame = Frame(root, bg="Red", borderwidth=30)
other_frame = Frame(root, bg="Yellow", borderwidth=30)
main_frame.place(relx = 0.5, rely = 0.1, anchor = "center")
other_frame.place(relx = 1.5, rely = 0.1, anchor = "center")
Label(main_frame, text="First Window").pack()
Button(main_frame, text="GO", command=second_screen).pack()
Label(other_frame, text="Second Window").pack()
Button(other_frame, text="BACK", command=main_screen).pack()
main_screen()
root.mainloop()
The advantage of using .place()
is you can animate the frame back and forth using a for loop.
from tkinter import *
root = Tk()
my_height = 600
my_width = 350
root.geometry(f"{my_height}x{my_width}")
# root.maxsize(my_height, my_width)
# first window
def main_screen():
global x1, y1, x2, y2
for i in range(1000):
x1 += 0.001
x2 += 0.001
main_frame.place(relx = x1, rely = y1, anchor = "center")
other_frame.place(relx = x2, rely = y2, anchor = "center")
main_frame.update()
other_frame.update()
def second_screen():
global x1, y1, x2, y2
for i in range(1000):
x1 -= 0.001
x2 -= 0.001
main_frame.place(relx = x1, rely = y1, anchor = "center")
other_frame.place(relx = x2, rely = y2, anchor = "center")
main_frame.update()
other_frame.update()
# FRAMES
x1, y1 = 0.5, 0.1
x2, y2 = 1.5, y1
main_frame = Frame(root, bg="Red", borderwidth=30)
other_frame = Frame(root, bg="Yellow", borderwidth=30)
main_frame.place(relx = 0.5, rely = 0.1, anchor = "center")
other_frame.place(relx = 1.5, rely = 0.1, anchor = "center")
Label(main_frame, text="First Window").pack()
Button(main_frame, text="GO", command=second_screen).pack()
Label(other_frame, text="Second Window").pack()
Button(other_frame, text="BACK", command=main_screen).pack()
root.mainloop()
Hope this helps!
Upvotes: 2
Reputation: 385970
The first thing you do in main_screen
is to destroy other_frame
. When you call second_screen
, it tries to use that frame as the parent for new widgets but it has been destroyed. That is why you get the error bad window path name ".!frame"
- it is bad because it has been destroyed and can no longer be used.
A simple solution is to simply not call other_frame.destroy()
. Instead, you can remove it from view with other_frame.pack_forget()
.
It's important to know that pack
works by placing objects in available space, and in the order that pack
was called. If you remove and add widgets once the app has started, that may affect the order in which the widgets appear.
In this specific case, since main_screen
and other_screen
are the only widgets directly in root it doesn't matter, and doesn't affect the reason why you got the error you got.
Upvotes: 2