13

Part of the GUI I'm building using tkinter has a pop-up window that says "Please wait while the program is running." then after it finishes the window goes away. I'm using the widget.after command to open the window and run the command. However if I pass the function I call arguments then the pop up window never occurs. Here's an example:

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

This runs fine and does what I want it to do, the window pops up while the backup runs, then the window closes after the backup. However, If I pass the and argument from the widget.after like the code below, the "please wait" message never shows up.

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 Answers 3

42

When you do this:

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

... You are telling Tkinter "run the command runBackup, and when it returns, use the result as an argument to after". Because runBackup returns None, the above is equivalent to:

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

Instead, you want to give after a reference to the function, rather than calling the function. If the command needs arguments, those can be given to after as additional arguments.

For example:

widget.after(10, self.runBackup, mybackup)
Sign up to request clarification or add additional context in comments.

1 Comment

just for completeness, the resulting call is widget.after(10, None) because a function that has no return statement returns None.
1

I would try functools.partial to wrap your call as in:

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

Or you could define a local function that takes no arguments but passes the parameter (which is in essence what functools.partial does).

2 Comments

While this is a perfectly acceptable solution, it's more complex than it needs to be. after is designed to take arguments, and use them when calling the function, the OP was just doing it wrong.
in this simple case you could just use a lambda to define an anonymous function instead of functools.partial: widget.after(10, lambda: self.runBackup(mybackup))
0

Add: Using Lambda function format, the function doesn´t fail after several recursive calls. eg:

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

    ...

(it´s very useful to update a time-clock at left-top of window, for example...)

1 Comment

Do you mean that .after(1000, lambda : abc(par)) is better for recursive calls than .after(1000, abc, par) ? Genuine question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.