How would I go about writing a command that fully closes the currently open tkinter programm. There are already a ton of threads regarding this, but I have been unable to find a solution that reliably closes all open tkinter windows. In my scenario, I am adding menus to each window with the option to close the current window, as well as close the whole programm. While closing the current window always works, closing the whole programm only works sporadically.
Things I have tried:
using root.quit() frequently leads to the "Python not responding" windows error message.
using root.destroy() will close the root window, and all toplevel windows, if I have not clicked on anything in them. Once I do use a toplevel window, it will not be ended by the root.destroy() command anymore.
using mytoplevel.destroy() will reliably close the currently active toplevel window.
I have written a simplified version of the code I am using, however, the windows don't do anything here, so the destroy command will always work.
import tkinter as tk
class MainWindow(tk.Frame):
def __init__(self, master = None):
b = tk.Button(master, text="Type_1", command=self.window_type_1)
b.pack()
self.load_menu(root)
tk.Frame.__init__(self, master)
def close(self, parent):
parent.destroy()
def window_type_1(self):
top = tk.Toplevel()
top.minsize(width = 600, height = 500)
self.load_menu(top)
def load_menu(self, parent):
menubar = tk.Menu(parent, tearoff=False)
parent.config(menu=menubar)
start_menu = tk.Menu(menubar, tearoff=False)
if parent == root:
start_menu.add_command(label="close", command=lambda: self.close(parent))
menubar.add_cascade(label="File", menu=start_menu)
else:
start_menu.add_command(label="Window close", command=lambda: self.close(parent))
start_menu.add_command(label="Programm close", command=lambda: self.close(root))
menubar.add_cascade(label="File", menu=start_menu)
root = tk.Tk()
mainwindow = MainWindow(master = root)
mainwindow.mainloop()
Calling destroy on the root window is generally the right solution, and is specifically the right solution in your example program. Destroying the root window will cause mainloop to exit, so unless you have more code after the call to mainloop and/or more code running in a separate thread, the program must exit.
I have Python 3.6.3. I'm trying to program a simple GUI app with Submit and Quit buttons. I've got this GUI code:
from tkinter import *
from sys import exit
...
some = True
stuff = False
here = "bar"
top = Tk()
submitButton = Button(top, text="Submit", command=lambda: submit(some, things, set, here)).pack(pady=50, side=LEFT)
exitButton = Button(top, text="Quit", command=exit).pack(pady=50, side=RIGHT)
top.mainloop()
However, upon running this code, my button labels are invisible:
And I need to resize the window, even only a little, in order to see them again:
Am I doing something wrong here, or is this a bug with tkinter?
Add an update call before your mainloop call.
top.update()
top.mainloop()
Also consider upgrading to python3.7, since a lot of tkinter problems for mac were fixed in 3.7.
How do I end a Tkinter program? Let's say I have this code:
from Tkinter import *
def quit():
# code to exit
root = Tk()
Button(root, text="Quit", command=quit).pack()
root.mainloop()
How should I define the quit function to exit my application?
You should use destroy() to close a Tkinter window.
from Tkinter import *
#use tkinter instead of Tkinter (small, not capital T) if it doesn't work
#as it was changed to tkinter in newer Python versions
root = Tk()
Button(root, text="Quit", command=root.destroy).pack() #button to close the window
root.mainloop()
Explanation:
root.quit()
The above line just bypasses the root.mainloop(), i.e., root.mainloop() will still be running in the background if quit() command is executed.
root.destroy()
While destroy() command vanishes out root.mainloop(), i.e., root.mainloop() stops. <window>.destroy() completely destroys and closes the window.
So, if you want to exit and close the program completely, you should use root.destroy(), as it stops the mainloop() and destroys the window and all its widgets.
But if you want to run some infinite loop and don't want to destroy your Tkinter window and want to execute some code after the root.mainloop() line, you should use root.quit(). Example:
from Tkinter import *
def quit():
global root
root.quit()
root = Tk()
while True:
Button(root, text="Quit", command=quit).pack()
root.mainloop()
#do something
See What is the difference between root.destroy() and root.quit()?.
def quit()
root.quit()
or
def quit()
root.destroy()
import tkinter as tk
def quit(root):
root.destroy()
root = tk.Tk()
tk.Button(root, text="Quit", command=lambda root=root:quit(root)).pack()
root.mainloop()
Illumination in case of confusion...
def quit(self):
self.destroy()
exit()
A) destroy() stops the mainloop and kills the window, but leaves python running
B) exit() stops the whole process
Just to clarify in case someone missed what destroy() was doing, and the OP also asked how to "end" a tkinter program.
I think you wrongly understood the quit function of Tkinter. This function does not require you to define.
First, you should modify your function as follows:
from Tkinter import *
root = Tk()
Button(root, text="Quit", command=root.quit).pack()
root.mainloop()
Then, you should use '.pyw' suffix to save this files and double-click the '.pyw' file to run your GUI, this time, you can end the GUI with a click of the Button, and you can also find that there will be no unpleasant DOS window. (If you run the '.py' file, the quit function will fail.)
The usual method to exit a Python program:
sys.exit()
(to which you can also pass an exit status) or
raise SystemExit
will work fine in a Tkinter program.
In case anyone wants to bind their Escape button to closing the entire GUI:
master = Tk()
master.title("Python")
def close(event):
sys.exit()
master.bind('<Escape>',close)
master.mainloop()
The easiest way would be to click the red button (leftmost on macOS and rightmost on Windows).
If you want to bind a specific function to a button widget, you can do this:
class App:
def __init__(self, master)
frame = Tkinter.Frame(master)
frame.pack()
self.quit_button = Tkinter.Button(frame, text = 'Quit', command = frame.quit)
self.quit_button.pack()
Or, to make things a little more complex, use protocol handlers and the destroy() method.
import tkMessageBox
def confirmExit():
if tkMessageBox.askokcancel('Quit', 'Are you sure you want to exit?'):
root.destroy()
root = Tk()
root.protocol('WM_DELETE_WINDOW', confirmExit)
root.mainloop()
you only need to type this:
root.destroy()
and you don't even need the quit() function cause when you set that as commmand it will quit the entire program.
you dont have to open up a function to close you window, unless you're doing something more complicated:
from Tkinter import *
root = Tk()
Button(root, text="Quit", command=root.destroy).pack()
root.mainloop()
In idlelib.PyShell module, root variable of type Tk is defined to be global
At the end of PyShell.main() function it calls root.mainloop() function which is an infinite loop and it runs till the loop is interrupted by root.quit() function. Hence, root.quit() will only interrupt the execution of mainloop
In order to destroy all widgets pertaining to that idlelib window, root.destroy() needs to be called, which is the last line of idlelib.PyShell.main() function.
I normally use the default tkinter quit function, but you can do your own, like this:
from tkinter import *
from tkinter.ttk import *
window = Tk()
window.geometry('700x700') # 700p x 700p screen
def quit(self):
proceed = messagebox.askyesno('Quit', 'Quit?')
proceed = bool(proceed) # So it is a bool
if proceed:
window.quit()
else:
# You don't really need to do this
pass
btn1 = Button(window, text='Quit', command=lambda: quit(None))
window.mainloop()
For menu bars:
def quit():
root.destroy()
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=quit)
menubar.add_cascade(label="menubarname", menu=filemenu)
root.config(menu=menubar)
root.mainloop()
I use below codes for the exit of Tkinter window:
from tkinter import*
root=Tk()
root.bind("<Escape>",lambda q:root.destroy())
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="exit",command=root.destroy).pack()
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="quit",command=quit).pack()
root.mainloop()
or
from tkinter import*
root=Tk()
Button(root,text="exit",command=exit).pack()
root.mainloop()
Code snippet below. I'm providing a small scenario.
import tkinter as tk
from tkinter import *
root = Tk()
def exit():
if askokcancel("Quit", "Do you really want to quit?"):
root.destroy()
menubar = Menu(root, background='#000099', foreground='white',
activebackground='#004c99', activeforeground='white')
fileMenu = Menu(menubar, tearoff=0, background="grey", foreground='black',
activebackground='#004c99', activeforeground='white')
menubar.add_cascade(label='File', menu=fileMenu)
fileMenu.add_command(label='Exit', command=exit)
root.config(bg='#2A2C2B',menu=menubar)
if __name__ == '__main__':
root.mainloop()
I have created a blank window here & add file menu option on the same window(root window), where I only add one option exit.
Then simply run mainloop for root.
Try to do it once
Of course you can assign the command to the button as follows, however, if you are making a UI, it is recommended to assign the same command to the "X" button:
def quit(self): # Your exit routine
self.root.destroy()
self.root.protocol("WM_DELETE_WINDOW", self.quit) # Sets the command for the "X" button
Button(text="Quit", command=self.quit) # No ()
There is a simple one-line answer:
Write - exit() in the command
That's it!
I tried to find out a solution for my problem, but I couldn't find one.
I am using Python27 on Windows 7.
I have an easy Tkinter GUI with a button:
import Tkinter
import sys
def close_window():
root.destroy()
sys.exit()
root = Tkinter.Tk()
#exit button
draw_button = Tkinter.Button(root, text="Quit", command = close_window)
draw_button.grid(row=1, column=1)
root.mainloop()
Now if I use the Quit button the program closes and there is not task left of the program. The problem is if someone uses the X-Button to close the Windows or for examples uses Alt+F4, the task is still running.
For later use I freeze the script to make an executable and if someone uses some method to close the program except the Quit button the task is still running. And if the task is still running he or she can't open the program again, because it is still running in the background and Windows raise an error that the program is still running.
I tried to add some commands after the mainloop but they are all ignored. How can I solve this problem?
Thanks for your help! Max
What about using WM_DELETE_WINDOW. For example:
import tkinter
import sys
def close_window():
root.destroy()
sys.exit()
def win_deleted():
print("closed");
close_window();
root = tkinter.Tk()
#exit button
draw_button = tkinter.Button(root, text="Quit", command = close_window)
draw_button.grid(row=1, column=1)
root.protocol("WM_DELETE_WINDOW", win_deleted)
root.mainloop()
This will close app with ctr+F4.
I was following along in a youtube tutorial:
https://www.youtube.com/watch?v=Zf-b2JVZs7g
When we got to sys.exit(0)
The Python shell seems to be responding but the window I create locks up instead of closing. The other weird thing is that when I run the debugger, the program operates as expected.
#Python 2.7.8
#Idle 2.7.8
#Tkinter 8.5.15
import sys
import Tkinter
import turtle
from Tkinter import *
def main():
root = Tk()
root.title("Draw!")
root.geometry("800x800")
cv = Canvas(root, width=600, height=600)
cv.pack(side=LEFT)
t = turtle.RawTurtle(cv)
screen = t.getscreen()
screen.setworldcoordinates(0,0,600,600)
frame = Frame(root)
frame.pack(side = RIGHT, fill = BOTH)
screen.tracer(0)
def quitHandler():
print ("Goodbye")
sys.exit(0)
##raise SystemExit
##exit()
quitButton = Button(frame, text="Quit", command = quitHandler)
quitButton.pack(side=BOTTOM)
def clickHandler(x,y):
t.goto(x,y)
screen.update()
screen.onclick(clickHandler)
def dragHandler(x,y):
t.goto(x,y)
screen.update()
t.ondrag(dragHandler)
root.mainloop()
if __name__ == "__main__":
main()
In the comments of the video there are two things that stick out to me but I can't figure out why sys.exit(0) isn't working for me like it worked for him:
He's using Python 3
Other people are having this same problem and there aren't any answers that I can see.
My guess is that it's a version problem but (as a n00b) I don't know what the problem is.
Add the line root.destroy() to your quitHandler function. It will clean up the Tkinter process that is otherwise left behind. I tested it and that fixes the issue for me.
(Code removed)
Update
From Terry Jan Reedy's comment:
The details of Python shutdown have changed from version to version,
even within 3.x. I personally would put root.destroy() but not
sys.exit() in a quit handler, and would let Python exit normally after
mainloop() and main() call return. Since printing 'goodbye' does not
print to the gui, and could fail (if you run the app with pythonw on
windows), I would put the print after the main() call.
So it would be
def quitHandler():
root.destroy()
and print at the very end of the code.
You can do it very easily like this:
def quit():
import sys;sys.exit()
widget = Button(root,text="Quit",width=1,fg="red",command=quit).grid(row=1,column=1)
If you use this code you can customize your bottom more.
def quitHandler():
print ("Goodbye")
root.destroy()
sys.exit(0)
quitButton = Button(frame, text="Quit", command = quitHandler)
quitButton.pack(side=BOTTOM)
This will work fine.