Invalid command name while executing ("after" script)
Asked Answered
C

6

13

As solve this problem? I'm running this code, window is created, but in console appears message on the error. I think problem the fact that is "after" loop not terminate but the window already destroyed.

Code:

import Tkinter as tk
import time

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.label = tk.Label(text="")
        self.label.pack()
        self.update_clock()
        self.root.mainloop()

    def update_clock(self):
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.root.after(1000, self.update_clock)

app=App()

A message in console:

invalid command name "66120320callit"
while executing
"66120320callit"
("after" script)

Sorry for my small information in first post. I'm using Spyder IDE, and bugs see in spyder console, wherein run repeatedly my code. A description this bugs I find in the python bug tracker as "wait_variable hangs at exit"

Cracker answered 2/10, 2014 at 20:19 Comment(2)
That's strange. It works on my machine. (once I correct the indentation on the lines following def __init__)Petronella
works for me as well!Jaime
P
14

If you destroy the window, whatever "after" jobs that have already been scheduled may run. If the window is destroyed and this job interacts with a widget that has been deleted, you'll get this error.

You can either put a try around the code and ignore such an error, check that the window exists before trying to configure it, or put a handler in for when the main window is destroyed to delete any pending "after" jobs.

Pudgy answered 2/10, 2014 at 23:35 Comment(2)
If you have a manual quit button, you can use the after_cancel() method to cancel an after method before calling root.destroy() to kill your program. Documentation here: effbot.org/tkinterbook/widget.htmJeffrey
The link above is dead. Found it on the wayback machine: web.archive.org/web/20201112030233/http://effbot.org/…Aldous
R
9

TL;DR: Use tkinter.Tk.quit()

Background

I was getting these 'errors' as well. They're not actual exceptions, they're just annoying to see being spammed in the terminal when running unittests.

I had tried a lot of things, including overriding the after method in tkinter.Tk to keep track of any queued methods and then calling tkinter.Tk.after_cancel() automatically before calling tkinter.Tk.destroy() as @GabrielStaples commented.

So I was getting these errors even though there were no queued after methods at the point of destroy() being called.

My solution

What worked for me was calling tkinter.Tk.quit() to destroy the window instead of destroy(). I read that quit() doesn't stop the mainloop but it seems fine. Any methods queued by after aren't called after quit() has been called.

Perhaps somebody could explain any consequences I'm not aware of if there are any

Rainier answered 12/6, 2020 at 5:58 Comment(1)
.quit() doesn't destroy the window. It only stops the .mainloop() that is currently running.Aldous
C
1

I had this problem because my module was named "setup" and I also had a setup.py file. When calling setup.py somecommand, you will get "invalid command name 'somecommand'".

Cornerwise answered 13/9, 2017 at 15:31 Comment(0)
L
1

I had this problem and solved by just using the plain Python's exit() instead of Tkinter's root.destroy() or tkinter.Tk.quit().

Limited answered 21/2, 2023 at 4:6 Comment(0)
S
1

What worked for me was creating an exit button that ran a function when clicked, the function would just have the below 2 lines in it:

self.withdraw()
self.quit()

This allowed the GUI to be closed successfully and would then continue running the rest of the code (if any) in the script.


Editing your code above to the following fixed it for me:

import tkinter as tk
import time

class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.label = tk.Label(text="")
        self.label.pack()
        
        self.buttonCloseWindow = tk.Button(self, text='Close Window', command=self.close_window)
        self.buttonCloseWindow.pack()
        
        self.update_clock()
        self.mainloop()

    def close_window(self):
        self.withdraw()
        self.quit()

    def update_clock(self):
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.after(1000, self.update_clock)

app=App()

I hope this helps!

Scauper answered 29/10, 2023 at 18:47 Comment(0)
S
0

A possible solution to this issue is to define a protocol for when the window is deleted (closed) WM_DELETE_WINDOW. In my example, I'm prompting the user with a Yes/No messagebox to make sure the closing was not accidental. But if you are just testing, you can remove that, and the close button will withdraw() and quit() the application.

import tkinter as tk
import tkinter.messagebox
import time

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.label = tk.Label(text="")
        self.label.pack()
        self.update_clock()

    def update_clock(self):
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.after(1000, self.update_clock)

def on_closing():
    response=tkinter.messagebox.askyesno('Exit','Are you sure you want to exit?')
    if response:
        app.withdraw()
        app.quit()

if __name__ == "__main__":
    app = App()
    app.protocol("WM_DELETE_WINDOW", on_closing)
    app.mainloop()
Southeastwards answered 14/11, 2023 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.