我未嵌套的功能,看看是什么错误。您遇到的问题是函数尝试访问另一个函数范围中定义的变量。这是行不通的。您必须嵌套函数以便它们的作用域重叠,正如您所做的那样 - 这很尴尬 - 或者您必须使用全局变量 - 这样做不那么笨拙,但仍然很尴尬 - 或者必须从函数传递变量名起作用。
但是,因为您在这里使用回调 - 这是相当先进的! - 执行第三个选项比较复杂。如果你真的想得到这个工作,我会建议一个面向对象的方法。但坦率地说,我会建议从一开始的程序员开始比这更简单。
最重要的是您习惯了范围规则。至少,我可以用你的代码解释。以下是你正在获取的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)
通常蟒蛇假定在函数中定义的变量是局部变量创建一个函数的命名空间中的全局变量,所以你要明确的告诉它。这就是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()
你被存储在thirdcontent
None
,因为pack()
方法没有返回值。如果您想保留对Label
的引用,则必须先单独保存该引用,然后再保存pack()
,就像我在上面的new_frame
中那样。
其次,从我的replace
方法中可以看到,你实际上并不需要销毁该框架来改变标签文本或的按钮命令!上面仍然破坏前三个框架,只是为了说明它如何工作。
希望这会让你开始!祝你好运。
你不应该使用“从X导入*”的指令,因为它拉该模块的所有符号为全局命名空间。这可能导致冲突(并且模糊错误)。相反,只需'导入Tkinter'并使用完全限定的名称(如果必须缩短一些,可以'将Tkinter导入为tk'并参考tk.whatever]。 – user505255 2011-06-01 03:03:31
感谢您的意见,我只是复制了我在其他示例中看到的内容。 – Verdigriss 2011-06-01 03:42:44