[英]How do I reinitialize a frame in tkinter?
我有一个程序,它处理很多从文件中的数据创建对象的问题,并且能够编辑对象,然后将它们保存在同一个文件中。 我正在实现一个 GUI,我正在使用 tkinter 来完成它。 我面临的问题是当我在帧之间来回跳转时帧不更新的问题,因为构造函数方法只在程序开始时运行一次,这是我在屏幕上生成大部分小部件的地方。 以下是我想要完成的示例:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (Homescreen, Menuscreen):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class Homescreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
with open("test.txt", "r") as f:
text = f.readline()
tk.Label(self, text = text).pack()
tk.Button(self, text = "next page", command = lambda: controller.show_frame(Menuscreen)).pack()
class Menuscreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.entry = tk.StringVar()
tk.Entry(self, textvariable = self.entry).pack()
tk.Button(self, text = "back to page", command = self.writeToFile).pack()
def writeToFile(self):
with open("test.txt", "w") as f:
f.writelines(self.entry.get())
self.controller.show_frame(Homescreen)
app = App()
app.geometry("500x400")
app.mainloop()
如果我有一个只有一个简单单词的Homescreen
文件,我会在主屏幕中将其打印在屏幕上。 然后我移动到第二个框架Menuscreen
,在这里我允许用户输入另一个词,然后我将这个词存储在同一个文本文件中。 然后程序将我们带回主Homescreen
,但问题是打印出来的单词仍然是第一个单词,而不是文本文件中更新的单词。
我尝试使用方法.update()
和.destroy()
,在我执行frame.tkraise()
之前的一行,但是.update()
方法没有做任何事情,当我使用.destroy()
方法时,我收到一条错误_tkinter.TclError: bad window path name
您无法更改“打印出来的单词”,因为Homescreen
的构造函数只运行一次。 您需要另一种方法来在您举起Frame
时更改条目。 更改在下面评论。 只有 4 个。
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (Homescreen, Menuscreen):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container):
frame = self.frames[container]
#update the label
if container is Homescreen: frame.update_label()
frame.tkraise()
class Homescreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#keep a reference to the label so it can be modified
self.label = tk.Label(self)
self.label.pack()
tk.Button(self, text = "next page", command = lambda: controller.show_frame(Menuscreen)).pack()
self.update_label()
#update the label
def update_label(self):
with open('test.txt', 'r') as f:
self.label['text'] = f.read()
class Menuscreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.entry = tk.StringVar()
tk.Entry(self, textvariable = self.entry).pack()
tk.Button(self, text = "back to page", command = self.writeToFile).pack()
def writeToFile(self):
with open('test.txt', 'w') as f:
f.write(self.entry.get())
#go back to homescreen
self.controller.show_frame(Homescreen)
app = App()
app.geometry("500x400")
app.mainloop()
如果你想让你的脚本更容易使用,我在下面重构了它,并留下了评论。
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
#you do not need `container`
#using root as the master makes it a more natural controller
#you were using it more like a proxy
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
#you created a convention with your class names of using "screen"
#use some kind of "screen" for everything that contains or directly relates to them
self.screens = {}
#don't "juggle"
#create a var, and use it
for screen in (Menuscreen, Homescreen):
self.screens[screen] = screen(self)
self.screens[screen].grid(row=0, column=0, sticky="nsew")
#renamed to reflect that it relates to your screens
def show_screen(self, screen):
target = self.screens[screen]
if screen is Homescreen: target.update_label()
target.tkraise()
class Homescreen(tk.Frame):
#whatever you put in master becomes the `self.master` of this widget
#ie.. we are keeping the names the same
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.label = tk.Label(self)
self.label.pack()
#this line illustrates how the root is the controller
tk.Button(self, text="next page", command=lambda: master.show_screen(Menuscreen)).pack()
#init the label text
self.update_label()
def update_label(self):
with open('test.txt', 'r') as f:
self.label['text'] = f.read()
class Menuscreen(tk.Frame):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.entry = tk.StringVar()
tk.Entry(self, textvariable=self.entry).pack()
tk.Button(self, text="back to page", command=self.writeToFile).pack()
def writeToFile(self):
with open('test.txt', 'w') as f:
f.write(self.entry.get())
#illustrates again how the root is the controller
self.master.show_screen(Homescreen)
#this is good practice
if __name__ == "__main__":
app = App()
app.geometry("500x400")
app.mainloop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.