代码之家  ›  专栏  ›  技术社区  ›  Miraj50 user2991863

重复打开和销毁窗口时使用全局变量的问题

  •  2
  • Miraj50 user2991863  · 技术社区  · 7 年前

    我正在构建一个小应用程序。

    当一个人运行这个最小的程序时,他/她会看到开始屏幕上有一个登录按钮( 开始 ),它有一个打开文本框的按钮和一个注销按钮。单击“注销”按钮时,将销毁 然后又开始了 开始 .

    单击登录->单击“输入成绩”->单击注销->单击登录->单击“输入等级”->错误:( can't invoke "grid" command: application has been destroyed )

    globals 埃格拉德 globals() 或否)。如果是,则只需放置现有的一个。但是当页面被销毁时,它仍然在 因此,当小部件被破坏时,如果我们试图再次放置它,它将给出一个错误。

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

    1 回复  |  直到 7 年前
        1
  •  4
  •   Mike - SMT    7 年前

    出现此错误的主要原因是当您第一次销毁包含文本小部件的容器时注销。即使小部件(框架)存在于全局名称空间中,但您已经销毁了它被分配到的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()
    

    下面是一个代码的类示例。

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