Tkinter:按钮打开新窗口并关闭当前窗口

1 投票
2 回答
4117 浏览
提问于 2025-04-17 16:52

我正在创建一个“定义测试”类型的程序(用户输入单词、词性和每个单词的同义词,然后程序会对用户进行相关知识的测试)。在最后的窗口(测试窗口)中,我的布局是这样的:

1/25 What is the definition of _word_? # number out of total + prompt
Definition: _entry_ # entry fields for information
Part of Speech: _entry_
Next Help Quit # buttons; 'Next' checks the info and goes to the next word 
# 'Help' shows the info and goes to the next word
# 'Quit' force-quits the program
Tries Left: 5 # how many tries before the info is shown

我遇到的问题是关于“帮助”按钮的。通常情况下,只要输入错误信息5次,就能成功打开“帮助”窗口;但是,它仍然会保留原来的单词(那个无法回答的单词)在打开状态。当这个新窗口关闭后,新单词会出现,但会有两个窗口:一个是新单词,一个是旧单词。此外,“帮助”按钮本身也会引发一个错误:

>>> 

Traceback (most recent call last):
  File _filepath_, line 455, in <module>
    main()
  File _filepath_, line 68, in main
    test(screenDim, test_dict)
  File _filepath_, line 451, in test
    root.destroy()
  File "C:\Python2.7.3\lib\lib-tk\Tkinter.py", line 1728, in destroy
    self.tk.call('destroy', self._w)
TclError: can't invoke "destroy" command:  application has been destroyed

这是我的 test 函数(我删减了一些代码,以便更容易找到问题):

def test(screenDim, test_dict):
    class TestWords:
        def __init__(self, master):
            w, h = screenDim[0], screenDim[1]
            rootW, rootH, xPos, yPos = int(float(w)/3), int(float(h)/4), w/2 - (w/6), h/2 - (h/8)
            self.frame = Frame(master)
            self.frameB = Frame(self.frame)
            self.frameE = Frame(self.frame)
            self.posE = Entry(self.frameE, width = 50, justify = CENTER)
            self.defE = Entry(self.frameE, width = 50, justify = CENTER)
            self.posE.grid(row = 1, column = 2, pady = 5)
            self.defE.grid(row = 2, column = 2, pady = 5)
            # there are a few other widgets/frames that don't pertain to this problem
            self.goButton = Button(self.frameB, text = 'Next', command = self.getInfo, width = 10)
            self.helpButton = Button(self.frameB, text = 'Help', command = self.getHelp, width = 10)
            self.quitButton = Button(self.frameB, text = 'Quit', command = self.quitBox, width = 10, fg = 'red')
            self.goButton.grid(row = 1, column = 1, padx = 10)
            self.helpButton.grid(row = 1, column = 2, padx = 10)
            self.quitButton.grid(row = 1, column = 3, padx = 10)
            master.geometry("%sx%s+%s+%s" % (rootW, rootH, xPos, yPos))
            self.frameE.grid(row = 3, pady = 5)
            self.frameB.grid(row = 4, padx = rootW/4 - 60, pady = 5)
            self.frame.grid()
        def quitBox(self):
            import sys
            sys.exit('Program Terminated.')
        def getHelp(self):
            triesLeft = 0
            self.frame.quit()
            root.destroy()
        def getInfo(self):
            info = (self.posE.get(), self.defE.get())
            self.frame.quit()
            return info
    class GetHelp:
        def __init__(self, master):
            w, h = screenDim[0], screenDim[1]
            rootW, rootH, xPos, yPos = int(float(w)/4), int(float(h)/4), w/2 - (w/8), h/2 - (h/8)
            self.frame = Frame(master)
            self.frameB = Frame(self.frame)
            self.goButton = Button(self.frameB, text = 'Next', command = self.frame.quit, width = 10)
            self.quitButton = Button(self.frameB, text = 'Quit', command = self.quitBox, fg = 'red', width = 10)
            self.goButton.grid(row = 1, column = 1, padx = 5)
            self.quitButton.grid(row = 1, column = 2, padx = 5)
            self.frameB.grid(row = 2, padx = rootW/4 - 20, pady = 5)
            master.geometry("%sx%s+%s+%s" % (rootW, rootH, xPos, yPos))
            self.frame.grid()
            # again, a few widgets were removed for brevity
        def quitBox(self):
            import sys
            sys.exit('Program Terminated.')
    n, words, reviewWords = len(test_dict.keys()), test_dict.keys(), []
    shuffle(words)
    for i in range(n):
        word, triesLeft = words[i], 4
        while triesLeft >= 0:
            root = Tk(className = ' Definition Tester')
            root.columnconfigure(0, weight=1)
            root.rowconfigure(0, weight=1)
            app = TestWords(root)
            root.mainloop()
            try:
                info = app.getInfo()
            except TclError:
                info = ('', '')
            if info[0] == test_dict[word][0] and info[1] in test_dict[word][1]:
                del words[i]
                root.destroy()
                break
            elif triesLeft == 0:
                reviewWords.append(word)
                root = Tk(className = ' Definition Tester')
                root.columnconfigure(0, weight=1)
                root.rowconfigure(0, weight=1)
                app = GetHelp(root)
                root.mainloop()
                break
            else:
                triesLeft -= 1
                root.destroy()

程序在尝试次数用完后会自动显示帮助窗口。因此,“帮助”按钮会将 triesLeft 设置为0。然而,这似乎并没有打开窗口。谢谢!

2 个回答

1

你需要在这个函数里修改tkinter的变量,然后关闭当前窗口,再打开一个新的窗口。

def new_window():
    current_tkinter_variable.quit()
    new_variable=Tk()
    #carry on
2

你需要重新设计你的方案,确保只创建一个主窗口,并且只运行一个 mainloop。与其反复创建和销毁主窗口,不如创建和销毁 Toplevel 的实例。因为 Tkinter 本身并不支持创建和销毁多个主窗口。

撰写回答