1

我正在使用 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()

类 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()

我是一个大菜鸟,但这需要我做很多工作才能制作,而且我真的被困在了我的位置,所以我可以使用一些创造性的输入。我希望这个程序暂停框架并允许用户在 value 变量中为以下每个对象类型输入内容:方面,将包含组,将包含成员(像树形图一样组织)。

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

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

4

1 回答 1

0

让我们从主要错误开始:

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

当 Python 到达这一行时,它会计算self.createGroups(aspect=a)并将返回值传递给command. 所以self.createGroups(aspect=a)最终被调用。相反,您真的想传递一个回调函数以便command稍后调用(当done下次按下按钮时)。

试图通过重新配置done回调来管理控制流是自找麻烦。我们不仅必须创建aspect = a已经绑定了正确参数(例如 )的函数,因此我们有一个函数需要零参数,就像完成回调所期望的那样,而且(甚至更难)我们必须识别何时重置done从 createMembers 到 createGroups 并返回到 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

createAspect这将来自的大部分代码createGroupcreateMembers所有代码组合到一个生成器中。可以重构cycle_done(成为迭代(较小)生成器的生成器),但这样做会增加解决方案的复杂性。让我们先让这个解决方案工作,然后(如果您有兴趣)我们可以担心重构。

于 2012-12-10T23:23:48.097 回答