Python 重复打开和销毁窗口时使用全局变量的问题
我正在构建一个小应用程序 当一个人运行这个最小的程序时,他/她会看到开始屏幕上有一个登录按钮。当点击它时,窗口被破坏,一个新窗口被创建homeP,它有一个打开文本框的按钮和一个注销按钮。单击注销按钮时,会销毁homeP并再次启动 复制我的问题的步骤: 单击登录->单击输入等级->单击注销->单击登录->单击输入等级->错误:无法调用网格命令:应用程序已被销毁 这是因为我一直在使用globals。正如大家所看到的,我想防止帧相互堆叠,因此我检查是否制作了eGrade帧,即是否在全局中。如果是,则只需放置现有的一个。但是当页面被销毁时,它仍然在全局中,因此,如果我们试图在小部件被销毁时再次放置它,它将给出一个错误Python 重复打开和销毁窗口时使用全局变量的问题,python,python-3.x,tkinter,Python,Python 3.x,Tkinter,我正在构建一个小应用程序 当一个人运行这个最小的程序时,他/她会看到开始屏幕上有一个登录按钮。当点击它时,窗口被破坏,一个新窗口被创建homeP,它有一个打开文本框的按钮和一个注销按钮。单击注销按钮时,会销毁homeP并再次启动 复制我的问题的步骤: 单击登录->单击输入等级->单击注销->单击登录->单击输入等级->错误:无法调用网格命令:应用程序已被销毁 这是因为我一直在使用globals。正如大家所看到的,我想防止帧相互堆叠,因此我检查是否制作了eGrade帧,即是否在全局中。如果是,则只
from tkinter import *
def Start():
global startS
startS = Tk()
loginButton = Button(startS, text='Login', bg='blue', fg='white', command=Login)
loginButton.grid()
startS.mainloop()
def Home():
global homeP
homeP = Tk()
enterButton = Button(homeP, text='Enter Grades', bg='blue', fg='white', command=enterG)
enterButton.grid(row=0, column=0, sticky="w")
logoutButton = Button(homeP, text='LogOut', bg='brown', fg='white', command=Logout)
logoutButton.grid(row=0, column=1, sticky="e")
homeP.mainloop()
def enterG():
global homeP
global eGrade
if 'eGrade' not in globals(): #Prevent Frames from stacking up on one another
eGrade = Frame(homeP)
enterGrades = Text(eGrade, width=64, height=10)
enterGrades.grid(row=0, column=0, sticky="ewns")
eGrade.grid(row=1, column=0, columnspan=2, sticky="ns")
else:
eGrade.grid(row=1, column=0, columnspan=2, sticky="ns")
# for name, value in globals().copy().items():
# print(name, value)
def Logout():
global homeP
homeP.destroy()
Start()
def Login():
global startS
startS.destroy()
Home()
Start()
因此,我想从专家那里了解一些关于使用globals是否是一种好的做法以及如何避免这个问题的建议。出现此错误的主要原因是当您第一次注销保存文本小部件的容器时。即使小部件框架存在于全局名称空间中,但您已经销毁了它分配给的tkinter实例。因此不能再适用于它 这是重新创建Tk实例而不是仅使用一个实例并管理其中的数据的直接结果 我的示例将把您的代码浓缩为更简单的内容,并为您提供一个良好的起点。我们将在这里为文本框中的文本创建一个全局跟踪变量。这将允许我们在注销时保存数据,然后在重新登录时重新应用数据。因此保留了旧文本
import tkinter as tk
def Home():
clear_widgets()
tk.Button(root, text='Enter Grades', bg='blue', fg='white', command=enterG).grid(row=0, column=0, sticky="w")
tk.Button(root, text='LogOut', bg='brown', fg='white', command=logout).grid(row=0, column=1, sticky="e")
def enterG():
global txt
if txt == None:
txt = tk.Text(root, width=64, height=10)
txt.grid(row=1, column=0, columnspan=2, sticky="ns")
txt.insert(1.0, text_data)
def logout():
global txt, text_data
text_data = txt.get(1.0, "end-1c")
clear_widgets()
txt = None
tk.Button(root, text='Login', bg='blue', fg='white', command=login).grid(row=0, column=0)
def clear_widgets():
for widget in root.winfo_children():
widget.destroy()
def login():
# some method of checking login credentials.
Home()
root = tk.Tk()
text_data = ""
tk.Button(root, text='Login', bg='blue', fg='white', command=login).grid(row=0, column=0)
root.mainloop()
然而,迟早你会想要开始在OOP中编码。这是一个很好的选择,它将使我们能够避免全球的一切。在一个类中,我们可以使用一种叫做class属性的东西,它可以从任何方法或class函数中访问,而无需定义全局属性
下面是一个代码的类示例
import tkinter as tk
class Example(tk.Tk):
def __init__(self):
super().__init__()
self.text_data = ""
self.txt = None
tk.Button(self, text='Login', bg='blue', fg='white', command=self.login).grid(row=0, column=0)
def home(self):
self.clear_widgets()
tk.Button(self, text='Enter Grades', bg='blue', fg='white', command=self.enter_g).grid(row=0, column=0, sticky="w")
tk.Button(self, text='LogOut', bg='brown', fg='white', command=self.logout).grid(row=0, column=1, sticky="e")
def enter_g(self):
if self.txt == None:
self.txt = tk.Text(self, width=64, height=10)
self.txt.grid(row=1, column=0, columnspan=2, sticky="ns")
self.txt.insert(1.0, self.text_data)
def logout(self):
self.text_data = self.txt.get(1.0, "end-1c")
self.clear_widgets()
self.txt = None
tk.Button(self, text='Login', bg='blue', fg='white', command=self.login).grid(row=0, column=0)
def clear_widgets(self):
for widget in self.winfo_children():
widget.destroy()
def login(self):
# some method of checking login credentials.
self.home()
Example().mainloop()
第一个突出的问题是多个Tk实例。你不应该这样做。@Mike SMT好的。对不起,我只是个初学者。我想知道更多关于这方面的情况。是的。我正在准备一个答案,这需要几分钟的时间。我想问,如果我按多次“输入成绩”按钮会怎么样。它将继续覆盖,不是吗?即使文本框已经打开。我之所以在文本框中使用框架,也是因为框架中还有其他小部件,但演示并不需要这些小部件。@Miraj50为此添加了一个修复程序。我们可以简单地保留一个跟踪变量,以查看文本小部件是否存在。@Miraj50是的,您是正确的,很好。坏习惯。我的大多数if语句都涉及!=。我开始一点一点地理解它。我想知道,从这个开始,我可以引入框架而不是文本,然后做同样的事情,对吗?因为我需要为我的应用程序插入更多的小部件。@Miraj50是的,您可以为任何需要的小部件使用框架。我只是简化了您的示例,以便更容易理解工作流。