我未嵌套的功能,看看是什麼錯誤。您遇到的問題是函數嘗試訪問另一個函數範圍中定義的變量。這是行不通的。您必須嵌套函數以便它們的作用域重疊,正如您所做的那樣 - 這很尷尬 - 或者您必須使用全局變量 - 這樣做不那麼笨拙,但仍然很尷尬 - 或者必須從函數傳遞變量名起作用。
但是,因爲您在這裏使用回調 - 這是相當先進的! - 執行第三個選項比較複雜。如果你真的想得到這個工作,我會建議一個面向對象的方法。但坦率地說,我會建議從一開始的程序員開始比這更簡單。
最重要的是您習慣了範圍規則。至少,我可以用你的代碼解釋。以下是你正在獲取的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