45

In Python using tkinter, what is the difference between root.destroy() and root.quit() when closing the root window?

Is one prefered over the other? Does one release resources that the other doesn't?

nbro
  • 15,395
  • 32
  • 113
  • 196
Gary Willoughby
  • 50,926
  • 41
  • 133
  • 199

4 Answers4

36

root.quit() causes mainloop to exit. The interpreter is still intact, as are all the widgets. If you call this function, you can have code that executes after the call to root.mainloop(), and that code can interact with the widgets (for example, get a value from an entry widget).

Calling root.destroy() will destroy all the widgets and exit mainloop. Any code after the call to root.mainloop() will run, but any attempt to access any widgets (for example, get a value from an entry widget) will fail because the widget no longer exists.

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • But what if we have multiple instance of `Tk()` and we use `root.destroy()` on on one of the instance, does that save us from the downsides of using more than one instance of `Tk()` because one of the interpreter is destroyed and we just have one instance left? – Delrius Euphoria Oct 26 '20 at 20:22
  • 2
    @CoolCloud you should never have multiple instances of `Tk()` anything you need to do with multiple windows can be and should be done with `Toplevel()`. – Mike - SMT Mar 02 '21 at 15:30
  • 1
    @Mike-SMT Essentially yes, but it never hurts if you can properly manage one more `Tk()`. – Delrius Euphoria Mar 02 '21 at 15:41
  • 2
    @CoolCloud where it is possible to manage multiple instance it is not a good idea especially for beginners. When you asked your question it implies that one can run into this issue from time to time but a beginner and in general it should be avoided to even do this. If you know what you are doing and clearly understand go for it if you want but a large portion if not a majority of people reading your comment should not think it is ok to use multiple instances of Tk. "Technically" you can but probably shouldn't. There are some easy ways to really mess things up with multiple instance of Tk. – Mike - SMT Mar 02 '21 at 15:49
28

quit() stops the TCL interpreter. This is in most cases what you want, because your Tkinter-app will also stop. It can be a problem, if you e.g. call your app from idle. idle is itself a Tkinker-app, so if you call quit() in your app and the TCL interpreter gets terminated, idle will also terminate (or get confused ).

destroy() just terminates the mainloop and deletes all widgets. So it seems to be safer if you call your app from another Tkinter app, or if you have multiple mainloops."

taken from http://www.daniweb.com/forums/thread66698.html

Community
  • 1
  • 1
ErikT
  • 606
  • 8
  • 15
  • 16
    This answer isn't quite correct. `root.quit()` does not "stop the TCL interpreter". It only causes `mainloop` to exit. The interpreter is still intact, as are all the widgets. Calling `root.destroy()` will destroy all the widgets _and_ exit `mainloop`. – Bryan Oakley Mar 21 '17 at 13:07
4

The tkinter.Tk "quit" method exits the "mainloop" event-handler, and "destroy" destroys all the embedded widgets and only then exits the "mainloop". So is "destroy" the better of the two? Well, sometimes not. If "destroy" fails to destroy all the widgets for some reason, then "mainloop" is never exited and Python locks up. It can be better to just let Python shut things down in an orderly manner at the end of the script.

For example, if you embed a Matplotlib plot in a Tkinter window, that is useful because Matplotlib's own widgets are somewhat clunky to use. Unfortunately, if you then try to close the window by clicking the usual "X" in the title-bar, the window closes alright but leaves Python running. If the script had been started from a terminal, you'd have to mash Ctrl-C for a couple of minutes to get the prompt back. The reason being that the window-close event is bound to "destroy" which does not destroy the Matplotlib objects but leaves them orphaned.

The fix is to bind the window-close event to "quit" instead. But... if the script is started in a Tkinter-based IDE like IDLE, then that creates a new problem in that the window does not close because IDLE holds Tkinter running. So now "destroy" must be added after the mainloop. Finally, all is well.

Below is a minimal example of a Matplotlib plot that can be inverted with a press of a Tkinter button. Its window can be closed without problems. But if the windows-close event had been bound to "destroy" instead of "quit" then a locked-up Python process would remain.

#!/usr/bin/env python3
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
root = tk.Tk()
data, = plt.plot([0,5,3,4,-5,3])
canvas = FigureCanvasTkAgg(plt.gcf(), master=root)
invert = lambda: (data.set_ydata(-data.get_ydata()), canvas.draw())
tk.Button(master=root, text="Invert", command=invert).pack()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=1)
root.protocol("WM_DELETE_WINDOW", root.quit)
root.mainloop()
root.destroy()

Edit: I'll add that by binding the window-close event to both methods, you can avoid adding a line after the "mainloop", should that be desirable for some reason:

root.protocol("WM_DELETE_WINDOW", lambda: (root.quit(), root.destroy()))
Dave Rove
  • 913
  • 1
  • 12
  • 18
0

My experience with root.quit() and root.destroy() ...

I have a dos python script, which calls a tkinter script (to choose from set of known values from combobox), then returns to the dos script to complete other things.

The TKinter script I've added onto the parent script. I may convert all to tkinter, but a combo works for the time being. It works in the following way:

To get rid of the windows box after selection was implemented, I needed to
1) root.quit() inside the callback function where all my keypresses were being processed.
2) root.destroy() after mainloop to destroy the windows box.

If I used root.destroy() inside the callback, I got an error message saying tkinter objects were no longer accessable.

Without the root.destroy() after mainloop, the windows box STAYED ONSCREEN until the whole parent script had completed.

m02ph3u5
  • 3,022
  • 7
  • 38
  • 51
Rupert
  • 21
  • 3