我取消嵌套函数以查看错误是什么。您遇到的问题是函数试图访问在另一个函数范围内定义的变量。那是行不通的。您要么必须嵌套函数,以便它们的范围重叠,就像您所做的那样——这很尴尬——或者你必须使用全局变量——这不那么尴尬,但仍然很尴尬——或者你必须从函数中传递变量名发挥作用。
但是,因为您在这里使用了回调——这是相当先进的!-- 执行第三个选项更复杂。如果你真的想让这个工作,我会建议一种面向对象的方法。但坦率地说,对于初学者来说,我建议从比这更简单的东西开始。
最重要的是你习惯了范围规则。至少,我可以用你的代码来解释。这是您得到的 NameErrors 的解释。
def Secondwindow():
firstframe.destroy()
secondframe = Frame(root)
secondframe.pack()
secondcontent = Label(secondframe, text = 'second window content').pack()
secondbutton = Button(secondframe, text = 'Next ->', command = Thirdwindow).pack()
def Thirdwindow():
secondframe.destroy()
thirdframe = Frame(root)
thirdframe.pack()
thirdcontent = Label(thirdframe, text = 'third window content').pack()
thirdbutton = Button(thirdframe, text = 'Next ->', command = Fourthwindow).pack()
这两个函数看起来几乎做同样的事情。但他们没有!原因如下:
def Secondwindow():
firstframe.destroy()
这一行指的是firstframe
,它是在全局范围内定义的(即在程序的“最低级别”。这意味着它可以从任何地方访问。所以你在这里没问题。
secondframe = Frame(root)
secondframe.pack()
secondcontent = Label(secondframe, text = 'second window content').pack()
secondbutton = Button(secondframe, text = 'Next ->', command = Thirdwindow).pack()
这些变量都定义在Secondwindow
. 这意味着它们只存在于Secondwindow
. 一旦你离开Secondwindow
,它们就不复存在了。这是有充分理由的!
def Thirdwindow():
secondframe.destroy()
现在你遇到了你的问题。这试图访问secondframe
,但secondframe
只定义在Secondwindow
. 所以你得到一个NameError
.
thirdframe = Frame(root)
thirdframe.pack()
thirdcontent = Label(thirdframe, text = 'third window content').pack()
thirdbutton = Button(thirdframe, text = 'Next ->', command = Fourthwindow).pack()
同样,这些都仅在ThirdWindow
.
现在,我无法解释完成这项工作所需的所有知识,但这里有一个基本提示。您可以通过说在函数的命名空间中创建全局变量
global secondframe
secondframe = Frame(root)
通常python假设函数中定义的变量是局部变量,所以你必须告诉它否则。就是global secondframe
这样。现在你真的不应该经常这样做,因为随着全局作用域充满了越来越多的变量,使用它们变得越来越难。函数创建更小的范围(或在某些上下文中称为“命名空间”),因此您不必跟踪所有名称(以确保您不会在两个地方使用相同的名称,或者其他更灾难性的错误)。
通常,为避免创建全局变量,您将让每个函数返回它通过调用定义的帧return secondframe
。然后,您可以为包含前一帧的每个函数添加一个函数参数,如def Thirdwindow(secondframe)
. 但是因为你使用回调来调用Secondwindow
等等,所以这个方法变得很棘手。这是一些通过使用lambda
语句解决问题的代码。
from Tkinter import *
root=Tk()
def Secondwindow(firstframe):
firstframe.destroy()
secondframe = Frame(root)
secondframe.pack()
secondcontent = Label(secondframe, text = 'second window content').pack()
secondbutton = Button(secondframe, text = 'Next ->', command = lambda: Thirdwindow(secondframe)).pack()
def Thirdwindow(secondframe):
secondframe.destroy()
thirdframe = Frame(root)
thirdframe.pack()
thirdcontent = Label(thirdframe, text = 'third window content').pack()
thirdbutton = Button(thirdframe, text = 'Next ->', command = lambda: Fourthwindow(thirdframe)).pack()
def Fourthwindow(thirdframe):
thirdframe.destroy()
fourthframe = Frame(root)
fourthframe.pack()
fourthcontent = Label(fourthframe, text = 'fourth window content').pack()
firstframe = Frame(root)
firstframe.pack()
firstcontent = Label(firstframe, text = 'first window content').pack()
firstbutton = Button(firstframe, text = 'Next ->', command = lambda: Secondwindow(firstframe)).pack()
root.mainloop()
但是解决这个问题的最好方法是使用面向对象的代码。不幸的是,这个话题太复杂了。它只会在已经很长的帖子中添加更多的措辞。老实说,我认为您应该先花一些时间来习惯函数和范围。
也就是说,我找到了一个时间来摆弄面向对象的变体。这里是:
from Tkinter import *
root=Tk()
class FrameRepeater(object):
def __init__(self, start=0, end=4):
self.frame = None
self.number = start
self.end = end
def new_frame(self):
if self.frame:
self.frame.destroy()
self.frame = Frame(root)
self.frame.pack()
self.content = Label(self.frame, text = 'window ' + str(self.number) + ' content')
self.content.pack()
self.button = Button(self.frame, text = 'Next ->', command = self.replace)
self.button.pack()
self.number += 1
def replace(self):
if self.number < self.end:
self.new_frame()
elif self.number >= self.end:
self.content.config(text='Press button again to quit')
self.button.config(command=self.quit)
def quit(self):
self.frame.destroy()
root.destroy()
exit()
FrameRepeater().new_frame()
root.mainloop()
有几点需要注意。首先,在像这样读的那些行中,有一个微妙的错误:
thirdcontent = Label(thirdframe, text = 'third window content').pack()
您存储None
在 中thirdcontent
,因为该pack()
方法没有返回值。如果要保留对 的引用,Label
则必须先保存引用,然后再pack()
单独保存,就像我在new_frame
上面所做的那样。
其次,从我的方法中可以看出replace
,实际上不必破坏框架来更改标签或按钮命令的文本!上面仍然破坏了前三帧,只是为了展示它是如何工作的。
希望这能让你开始!祝你好运。