Tk/Tkinter中的事件流出现问题



我正在使用Python 3.1和Tk.

我想循环使用我在这里定义的"NewDataFrame"对象的不同方法:

from tkinter import *
from tkinter import ttk
import string
root = Tk()
mainframe = ttk.Frame(root)
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
value = StringVar()
dataname = StringVar()
class MenuFrame:
def __init__(self, parent):
self.myParent = parent
self.menuFrame = ttk.Frame(self.myParent)
self.newButton = ttk.Button(self.myParent, text="new dataset", command=self.newClick)
self.loadButton = ttk.Button(self.myParent, text="load dataset", command=self.loadClick)
self.menuFrame.grid(column=0, row=0)
self.newButton.grid()
self.loadButton.grid()
def newClick(self):
self.instructions = ttk.Label(self.menuFrame, text="enter a name for your new dataset")
self.instructions.grid()
self.nameEntry = ttk.Entry(self.menuFrame, textvariable=dataname)
self.enterName = ttk.Button(self.menuFrame, text="enter", command=self.newData)
self.nameEntry.grid()
self.enterName.grid()

class NewDataFrame:

def __init__(self, parent, dataname):
self.myParent = parent
self.newDataFrame = ttk.Frame(parent)
self.dataSet = DataSet(dataname)
self.instructions = ttk.Label(self.newDataFrame)
self.instructions.configure(text="enter aspects of %s, separated by commas" % (self.dataSet.getName()))
self.enterBar = ttk.Entry(self.newDataFrame, textvariable=value)
self.enterButton = ttk.Button(self.newDataFrame, text="ENTER", command=self.enterClick)
self.doneButton = ttk.Button(parent, text="DONE", command=self.createAspects)
self.newDataFrame.grid()
self.enterBar.grid()
self.goingOn.grid()
self.instructions.grid()
self.enterButton.grid()
self.doneButton.grid()

我希望doneButton循环使用几个不同的命令,正如您在newDataSet框架的以下方法中看到的那样:

def createAspects(self):
for asp in (value.get().split(',')):
aspect = Aspect(self.dataSet.getName(), asp)
self.dataSet.addAspect(aspect)
for a in self.dataSet.getAspects():
self.createFile(i=a.getName())
self.instructions.configure(text="enter groups of %s, separated by commas" % (a.getName()))
self.doneButton.configure(command=self.createGroups(aspect=a))
def createGroups(self, aspect=""):
for gro in (value.get().split(',')):
print(gro)
group = Group(self.dataSet.getName(), aspect.getName(), gro)
aspect.addGroup(group)
for group in aspect.getGroups():
self.createFile(i=aspect.getName(), j=group.getName())
self.instructions.configure(text="enter members of %s, separated by commas" % (group.getName()))
self.doneButton.configure(command=self.createMembers(aspect=aspect, group=group))
def createMembers(self, aspect="", group=""):
for mem in (value.get().split(',')):
member = Member(self.dataSet.getName(), aspect.getName(), group.getName(), mem)
group.addMember(member)
for mem in group.getMembers():
self.createFile(i=aspect.getName(), j=group.getName(), k=mem.getName())
menuFrame = MenuFrame(mainframe)
root.mainloop()

我是一个大傻瓜,但这花了我很多工作来制作,我真的被困在原地,所以我可以使用一些创造性的投入。我希望这个程序暂停帧,并允许用户在值变量中为以下每种对象类型输入内容:方面,它将包含组,它将包括成员(像树状图一样组织)。

目前,该程序不在createGroup执行级别等待(我希望它等待另一次点击以进入createMember部分),而是要求用户在输入方面后立即输入成员。

我希望这不是太抽象,非常感谢任何试图提供帮助的人。

让我们从主要错误开始:

self.doneButton.configure(command=self.createGroups(aspect=a))

当Python到达此行时,它计算self.createGroups(aspect=a)并将返回值传递给command。所以self.createGroups(aspect=a)最终被称为。相反,您确实希望将回调函数传递给command,以便稍后调用(当下次按下done按钮时)

试图通过重新配置done回调来管理控制流会带来麻烦。我们不仅必须创建已经绑定了正确参数(例如aspect = a)的函数,这样我们就有了一个需要零参数的函数,就像完成回调所期望的那样,而且(甚至更难)我们必须识别何时重置从createMembers到createGroups的done回调,然后返回createAspect。我们将对控制流程进行微观管理。

如果我们能让Python来处理这些细节,那不是很好吗?

您正在寻找的是一个函数,您可以调用、暂停、稍后返回,并在之前暂停的位置继续。Python正是有这样的函数——一个生成器函数。

例如,

def gen():
for i in range(5):
print(i)
yield
mygen = gen().next
mygen()
mygen()

产生

0
1

请注意,每次调用mygen()时,执行都会继续,直到Python达到yield表达式。因此,第一次调用mygen()时,打印0,但第二次打印1。Python记得它最后一次屈服的地方,并在那一点上恢复。

因此,为了将这个想法应用于您的情况,您可以尝试使用以下内容:

class NewDataFrame:
def __init__(self, parent, dataname):
...
self.on_done = self.cycle_done().next
self.doneButton = ttk.Button(parent, text="DONE", command=self.on_done)
def cycle_done(self):
while True:
for asp in (value.get().split(',')):
aspect = Aspect(self.dataSet.getName(), asp)
self.dataSet.addAspect(aspect)
for aspect in self.dataSet.getAspects():
self.createFile(i=aspect.getName())
self.instructions.configure(
text="enter groups of %s, separated by commas" % (aspect.getName()))
yield
for gro in (value.get().split(',')):
print(gro)
group = Group(self.dataSet.getName(), aspect.getName(), gro)
aspect.addGroup(group)
for group in aspect.getGroups():
self.createFile(i=aspect.getName(), j=group.getName())
self.instructions.configure(
text="enter members of %s, separated by commas" % (group.getName()))
yield
for mem in (value.get().split(',')):
member = Member(self.dataSet.getName(), aspect.getName(), group.getName(), mem)
group.addMember(member)
for mem in group.getMembers():
self.createFile(i=aspect.getName(), j=group.getName(), k=mem.getName())
yield

这将来自createAspectcreateGroupcreateMembers的大部分代码合并到一个生成器中。可以重构cycle_done(成为一个迭代(较小)生成器的生成器),但这样做会给解决方案增加一些复杂性。让我们先让这个解决方案发挥作用,然后(如果您感兴趣的话)我们可以担心重构。

最新更新