10

In a class, in a function I am creating a Tkinter Canvas. This function is being called by another class, I would like for the Tkinter window to pop up for 30 seconds and then close itself. I have it call

master.mainloop()
time.sleep(30)
master.destroy() 

But I get an error

"elf.tk.call('destroy', self._w) _tkinter.TclError: can't invoke "destroy" command: application has been destroyed"

So how can I have it close itself?

nbro
  • 15,395
  • 32
  • 113
  • 196
EasilyBaffled
  • 3,822
  • 10
  • 50
  • 87
  • 1
    You need some kind of tutorial on what it means to run a GUI with an event loop, because until you get that, you're going to keep running into problems like this and not understanding them. (Sorry, I don't have one to recommend, but maybe someone else does.) It's worth noting that network servers and many other kinds of programs besides GUI apps are also built around event loops, so this is a pretty key thing to understand in programming beyond toy systems. – abarnert Mar 09 '13 at 01:57

2 Answers2

26

Don't use time.sleep() with tkinter. Instead, call the function after on the widget you want to close.

Here it is the most simple example:

import tkinter as tk

w = tk.Tk()
w.after(30000, lambda: w.destroy()) # Destroy the widget after 30 seconds
w.mainloop()
nbro
  • 15,395
  • 32
  • 113
  • 196
A. Rodas
  • 20,171
  • 8
  • 62
  • 72
  • what is the significance of as tk and tk.Tk() is that just renaming so its easier to write? – EasilyBaffled Mar 09 '13 at 02:04
  • @EasilyBaffled Yes, the [`import as`](http://www.python.org/dev/peps/pep-0221/) is used to avoid name clashes, and also to make the name modules shorter. I use it very ofter in Tkinter, but for this example `from Tkinter import Tk` and use `w = Tk()` is also valid. – A. Rodas Mar 09 '13 at 02:16
  • @EasilyBaffled: Another reason for `import Tkinter as tk` is so you can port your code to 3.x just by changing that first line to `import tinter as tk` without changing all the other places you reference the module. – abarnert Mar 09 '13 at 02:21
  • I am on osx with python3.4 and this is not working, the window does not destroy itself. – qed Nov 12 '14 at 19:44
4

The problem here is that mainloop() does not return until the GUI has shut down.

So, 30 seconds after the GUI has shut down and destroyed itself, you try to destroy it. And obviously that fails.

But you can't just move the sleep and destroy calls inside the main loop, because if you sleep in the middle of the main loop, the GUI will freeze up.

So, you need some kind of timer that will not stop the main loop. tkinter includes the after method for exactly that purpose. This answer gives a detailed example of using it.

Community
  • 1
  • 1
abarnert
  • 354,177
  • 51
  • 601
  • 671