使用按钮和绑定重复遍历列表

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)