-1

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()    
Tasmotanizer
  • 337
  • 1
  • 5
  • 15
  • Read [Python and Tkinter lambda function](https://stackoverflow.com/a/11005426/7414759) – stovfl Mar 01 '20 at 12:11
  • While that linked post seems to contain usefull information regarding the lambda function in general, it does appear to have no relevance in this case, as the variables given to the lambda function are unique and never modified, hence they are not changed and do not contain wrong information, like in the linked topics problem. Both menu entries "Window Close" & "Programm close" execute the correct method close with the correct parameter. The problem is, that root.destroy() does not close all toplevels reliably. – Tasmotanizer Mar 01 '20 at 12:40
  • ***"the variables given to the lambda function are unique and never modified, "***: The variable are local to `def load_menu(...` and are gone at `lambda` execution. ***""***: ***" not close all toplevels"***: Use a `parent` for the `tk.Toplevel(parent)` – stovfl Mar 01 '20 at 12:54

1 Answers1

0

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.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685