使用按钮和绑定重复遍历列表
Repeatedly iterating through a list, with buttons and bindings
所以我正在 TkInter (Python 3.4.3) 中进行数学测试。我只想对所有问题使用一个框架。我有一个包含所有字符串的列表(QStringList
,从另一个 .py 导入),它们用作标签的文本变量。
当用户按下 Return 或按钮时,我想迭代到列表中的下一项,因此显示了一个新问题。
使用我当前的代码,我只能成功执行一次。大概是因为 'CurrentQ' 变量每次都被设置回 0。
如何做到这一点,以便每次调用该函数时,都会显示下一个列表项?
此代码在我的 TestPage(tk.Frame):
class.
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
CurrentQ = 0
#QUESTION LABEL
self.CurrentQStringVar = tk.StringVar()
self.CurrentQString = tk.Label(self, textvariable=self.CurrentQStringVar,
anchor='w',fg="black", bg="yellow", font=STANDARD_FONT)
self.CurrentQString.grid(column=0,row=0,columnspan=2, sticky='EW')
self.CurrentQStringVar.set(QStringList[CurrentQ])
#ANSWER ENTRY BOX
self.UserAnsEntryVar = tk.StringVar()
self.UserAnsEntry = tk.Entry(self,textvariable=self.UserAnsEntryVar)
self.UserAnsEntry.grid(column=0,row=1,sticky='EW')
self.UserAnsEntry.bind("<Return>",
lambda event, CurrentQ=CurrentQ:
self.TestEnterKey(self,CurrentQ))
self.UserAnsEntryVar.set("")
#ANSWER BUTTON
self.UserAnsButtonVar = tk.StringVar()
self.UserAnsButton = ttk.Button(self,text="ENTER",
command= lambda: self.TestEnterKey(self,CurrentQ))
self.UserAnsButton.grid(column=0,row=2,columnspan=2, stick='EW')
def TestEnterKey(self,event,CurrentQ):
CurrentQ += 1
self.CurrentQStringVar.set(QStringList[CurrentQ])
return CurrentQ
我尝试使用 CurrentQ
作为函数中的参数,但也许我必须使用 lambda
。
编辑:我的实际 QStringList 非常长,并且包含其他(随机生成的)变量。所以为此我想最好只拥有...
QStringList = ["Q1","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10"]
首先,不要使用lambda
。 Lambda 有它的用途,但在 Tkinter 程序中很少需要它,而且它经常使代码更复杂而没有在 return 中提供任何东西。
相反,让从绑定和按钮调用的函数在需要时获取它需要的数据。由于绑定会发送事件而命令按钮不会,因此只需将事件参数设为可选。
此外,使 CurrentQ
成为对象的一个属性,这样它就可以很容易地访问,而不必四处传递。
def __init__(self,parent,controller):
...
self.CurrentQ = 0
...
self.UserAnsEntry.bind("<Return>",self.TestEnterKey)
...
self.UserAnsButton = ttk.Button(self,text="ENTER", command=self.TestEnterKey)
...
def TestEnterKey(self,event=None):
self.CurrentQ += 1
self.CurrentQStringVar.set(QStringList[self.CurrentQ])
循环浏览问题列表的另一种方法是始终使用列表中的第一项,然后将第一项移到末尾。 Python 有一个功能做类似的事情,让你无限期地循环列表。参见 itertools.cycle。
例如:
import itertools
...
self.questions = itertools.cycle(self.QStringList)
...
# this will always return the next question, looping
# back over the list as needed
next_question = self.questions.next()
最后,您可能要考虑 而不是 使用带标签的 StringVar
。除非您在多个地方使用 StringVar
,否则真的没有必要。没有它,您仍然可以更改标签中的文本,但您的项目中需要管理的对象就少了一个。
例如:
question = self.questions.next()
self.CurrentQString.configure(text=question)
所以我正在 TkInter (Python 3.4.3) 中进行数学测试。我只想对所有问题使用一个框架。我有一个包含所有字符串的列表(QStringList
,从另一个 .py 导入),它们用作标签的文本变量。
当用户按下 Return 或按钮时,我想迭代到列表中的下一项,因此显示了一个新问题。 使用我当前的代码,我只能成功执行一次。大概是因为 'CurrentQ' 变量每次都被设置回 0。 如何做到这一点,以便每次调用该函数时,都会显示下一个列表项?
此代码在我的 TestPage(tk.Frame):
class.
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
CurrentQ = 0
#QUESTION LABEL
self.CurrentQStringVar = tk.StringVar()
self.CurrentQString = tk.Label(self, textvariable=self.CurrentQStringVar,
anchor='w',fg="black", bg="yellow", font=STANDARD_FONT)
self.CurrentQString.grid(column=0,row=0,columnspan=2, sticky='EW')
self.CurrentQStringVar.set(QStringList[CurrentQ])
#ANSWER ENTRY BOX
self.UserAnsEntryVar = tk.StringVar()
self.UserAnsEntry = tk.Entry(self,textvariable=self.UserAnsEntryVar)
self.UserAnsEntry.grid(column=0,row=1,sticky='EW')
self.UserAnsEntry.bind("<Return>",
lambda event, CurrentQ=CurrentQ:
self.TestEnterKey(self,CurrentQ))
self.UserAnsEntryVar.set("")
#ANSWER BUTTON
self.UserAnsButtonVar = tk.StringVar()
self.UserAnsButton = ttk.Button(self,text="ENTER",
command= lambda: self.TestEnterKey(self,CurrentQ))
self.UserAnsButton.grid(column=0,row=2,columnspan=2, stick='EW')
def TestEnterKey(self,event,CurrentQ):
CurrentQ += 1
self.CurrentQStringVar.set(QStringList[CurrentQ])
return CurrentQ
我尝试使用 CurrentQ
作为函数中的参数,但也许我必须使用 lambda
。
编辑:我的实际 QStringList 非常长,并且包含其他(随机生成的)变量。所以为此我想最好只拥有...
QStringList = ["Q1","Q2","Q3","Q4","Q5","Q6","Q7","Q8","Q9","Q10"]
首先,不要使用lambda
。 Lambda 有它的用途,但在 Tkinter 程序中很少需要它,而且它经常使代码更复杂而没有在 return 中提供任何东西。
相反,让从绑定和按钮调用的函数在需要时获取它需要的数据。由于绑定会发送事件而命令按钮不会,因此只需将事件参数设为可选。
此外,使 CurrentQ
成为对象的一个属性,这样它就可以很容易地访问,而不必四处传递。
def __init__(self,parent,controller):
...
self.CurrentQ = 0
...
self.UserAnsEntry.bind("<Return>",self.TestEnterKey)
...
self.UserAnsButton = ttk.Button(self,text="ENTER", command=self.TestEnterKey)
...
def TestEnterKey(self,event=None):
self.CurrentQ += 1
self.CurrentQStringVar.set(QStringList[self.CurrentQ])
循环浏览问题列表的另一种方法是始终使用列表中的第一项,然后将第一项移到末尾。 Python 有一个功能做类似的事情,让你无限期地循环列表。参见 itertools.cycle。
例如:
import itertools
...
self.questions = itertools.cycle(self.QStringList)
...
# this will always return the next question, looping
# back over the list as needed
next_question = self.questions.next()
最后,您可能要考虑 而不是 使用带标签的 StringVar
。除非您在多个地方使用 StringVar
,否则真的没有必要。没有它,您仍然可以更改标签中的文本,但您的项目中需要管理的对象就少了一个。
例如:
question = self.questions.next()
self.CurrentQString.configure(text=question)