无法从tkinter widget.after函数传递参数

11

我正在使用tkinter构建的GUI的一部分,其中有一个弹出窗口显示“程序运行时,请稍等。”然后在完成后窗口会消失。我使用widget.after命令打开窗口并运行命令。但是,如果我传递函数调用参数,则弹出窗口永远不会出现。以下是示例:

def backupWindow
    self.restoreCB = Toplevel()

    message = "Please wait while backup runs"
    Label(self.restoreCB, text=message, padx=100, pady=20).pack()

    widget.after(10, self.runBackup)

def runBackup(self):
    <backup code>
    self.backupCB.destroy()

这段代码运行良好,实现了我的需求,窗口在备份运行时弹出,备份完成后关闭。然而,如果我像下面的代码一样从widget.after中传递参数<<please_wait>>,则“请稍等”消息将永远不会显示。

def backupWindow
    self.restoreCB = Toplevel()

    message = "Please wait while backup runs"
    Label(self.restoreCB, text=message, padx=100, pady=20).pack()

    widget.after(10, self.runBackup(mybackup))

def runBackup(self,mybackup):
    <backup code using mybackup>
    self.backupCB.destroy()
3个回答

38

当你执行以下操作时:

widget.after(10, self.runBackup(mybackup))

你告诉Tkinter "运行命令runBackup,当它返回时,将结果用作after的参数"。因为runBackup返回None,所以上述代码等同于:

self.runBackup(mybackup)
widget.after(10, None)

相反,你想要给after一个对函数的引用,而不是调用该函数。如果命令需要参数,则可以将这些参数作为附加参数传递给after

例如:

widget.after(10, self.runBackup, mybackup)

2
仅为完整性,结果调用是widget.after(10, None),因为没有返回语句的函数返回None - l4mpi

1

我建议使用functools.partial将您的调用进行包装,如下所示:

widget.after(10, functools.partial(self.runBackup, mybackup))

或者你可以定义一个本地函数,它不带参数但传递参数(这本质上就是 functools.partial 所做的)。


4
虽然这是一个完全可接受的解决方案,但其比必要的复杂。after 函数被设计为需要传入参数并在调用函数时使用它们,而该帖子作者只是使用不当。 - Bryan Oakley
3
在这个简单的情况下,您可以使用lambda来定义一个匿名函数,而不是使用functools.partialwidget.after(10, lambda: self.runBackup(mybackup)) - l4mpi

0

添加:使用Lambda函数格式,函数在多次递归调用后不会失败。 例如:

Function abc(par):
           stat-1
           stat-2
           ...
           stat-n
           root.after(1000, lambda : abc(par))

    ...

例如,在窗口左上角更新时钟非常有用...


你的意思是.after(1000, lambda : abc(par)).after(1000, abc, par)更适合递归调用吗?这是真正的问题。 - Ghislain Bugnicourt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接