Я удалил функции, чтобы увидеть, в чем была ошибка.Проблема в том, что функции пытаются получить доступ к переменным, определенным в области действия другой функции.Это не сработает.Вы должны либо вкладывать функции так, чтобы их области перекрывались, как вы это делали - что неудобно - или вам приходилось использовать глобальные переменные - что не так неудобно, но все же неудобно - или вам приходилось передавать имена переменных из функциифункционировать.
Однако, потому что вы используете обратные вызовы здесь - которые довольно продвинуты!- выполнение третьего варианта является более сложным.Если вы действительно хотите, чтобы это работало, я бы предложил объектно-ориентированный подход.Но, честно говоря, я бы посоветовал начать с чего-то более простого для начинающего программиста.
Самое важное, что вы привыкаете к определению правил.Это, по крайней мере, я могу объяснить с помощью вашего кода.Вот объяснение именных ошибок, которые вы получали.
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
метода, вам на самом деле не нужно уничтожать фрейм, чтобы изменить текст метки или команда кнопки!Выше все еще разрушает первые три кадра, просто чтобы показать, как это будет работать.
Надеюсь, это поможет вам начать!Удачи.