【问题标题】:I get an error: bad window path name ".!frame" when i press a button in the following code?当我按下以下代码中的按钮时出现错误:窗口路径名称错误“.!frame”?
【发布时间】:2020-10-16 01:57:48
【问题描述】:

我正在尝试制作两个不同的屏幕,并使用每个屏幕上的一个按钮将它们相互链接,并将它们作为命令分配给他们尊重的功能。

请帮助我了解为什么会出现以下错误:

错误的窗口路径名“.!frame”

当我按下以下代码中的按钮时。

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()

【问题讨论】:

  • 在调用 .destroy() 后,您无法重复使用 Frame。每次切换时都必须创建一个新框架 - 或使用 .pack_forget() 仅隐藏旧框架(在这种情况下,您只想在每个框架中创建小部件一次,而不是在每个开关上创建小部件)。

标签: python tkinter destroy


【解决方案1】:

你在main_screen做的第一件事就是摧毁other_frame。当您调用second_screen 时,它会尝试使用该框架作为新小部件的父级,但它已被销毁。这就是您收到错误bad window path name ".!frame" 的原因 - 它很糟糕,因为它已被破坏且无法再使用。

一个简单的解决方案是根本不调用other_frame.destroy()。相反,您可以使用 other_frame.pack_forget() 将其从视图中移除。

重要的是要知道pack 的工作原理是将对象放置在可用空间中,并且按照调用pack 的顺序。如果您在应用启动后删除并添加小部件,这可能会影响小部件的显示顺序。

在这种特定情况下,由于 main_screenother_screen 是唯一直接在 root 中的小部件,这无关紧要,并且不会影响您收到错误的原因。

【讨论】:

  • 这个问题是再打包的时候,第一个main_frame里面有两个按钮。
  • @10Rep main_frame 内部有按钮这一事实无关紧要,因为它们在main_frame 中,因此它们不会影响小部件在根窗口中的放置。但是你是正确的,这是使用包的一个弱点。感谢您的评论,我将添加一些澄清信息。
【解决方案2】:

问题是你在写other_frame.destroy()之前删除了框架other_frame。这使得程序的其余部分无法访问它,因为您销毁了它。

所以会有两种解决方案:一种是,正如 BryanOakley 所提到的,使用.pack()。另一种是使用.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()

使用.place() 的优点是您可以使用 for 循环来来回动画帧。

下面是代码:

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()

希望这会有所帮助!

【讨论】:

  • OP 使用的是pack,而不是place。此外,您在每个函数中调用了两次update(),在这两种情况下都是完全没有必要的。
  • @BryanOakley OP 并没有说他们不想使用place()。我同意place 不是最好的,但在这种情况下,它是最简单的解决方案。此外,如果您想为两个帧设置动画,您可以稍微编辑程序来实现这一点。
  • @BryanOakley 我已经想出了如何用 pack 来做。
【解决方案3】:

在框架上设置一个固定位置,并在每次需要时将它们堆叠在一起。

【讨论】:

    猜你喜欢
    • 2021-03-05
    • 2021-09-14
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多