Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 重复打开和销毁窗口时使用全局变量的问题_Python_Python 3.x_Tkinter - Fatal编程技术网

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

Python 重复打开和销毁窗口时使用全局变量的问题,python,python-3.x,tkinter,Python,Python 3.x,Tkinter,我正在构建一个小应用程序 当一个人运行这个最小的程序时,他/她会看到开始屏幕上有一个登录按钮。当点击它时,窗口被破坏,一个新窗口被创建homeP,它有一个打开文本框的按钮和一个注销按钮。单击注销按钮时,会销毁homeP并再次启动 复制我的问题的步骤: 单击登录->单击输入等级->单击注销->单击登录->单击输入等级->错误:无法调用网格命令:应用程序已被销毁 这是因为我一直在使用globals。正如大家所看到的,我想防止帧相互堆叠,因此我检查是否制作了eGrade帧,即是否在全局中。如果是,则只

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

当一个人运行这个最小的程序时,他/她会看到开始屏幕上有一个登录按钮。当点击它时,窗口被破坏,一个新窗口被创建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是的,您可以为任何需要的小部件使用框架。我只是简化了您的示例,以便更容易理解工作流。