closing all windows in python tkinter

Question:

I am working with tkinter library in python. I have a main window which has several buttons and when clicked those buttons a new window will popup which also has a button called cancel. I want to make that cancel button to all the windows.

I tried the following solution, which only closes the current window.

from tkinter import *
from tkinter import ttk
import  tkinter.messagebox

import datetime

import tkinter as tk


class AlertDialog:
    def __init__(self):
        self.invalidDiag = tk.Toplevel()
        invalidInput = tk.Label(master=self.invalidDiag,
                                text='Error: Invalid Input').grid(row=1, column=1)
        closeButton = tk.Button(master=self.invalidDiag,
                                text='Close',
                                command=self.invalidDiag.destroy).grid(row=2, column=1)

    def start(self):
        # self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
        self.invalidDiag.wait_window()


class  QuitDialog():

    def __init__(self, ):
        self.quitDialog = tk.Toplevel()
        warnMessage = tk.Label(master=self.quitDialog,
                                text='Are you sure that you want to quit? ').grid(row=1, column=1)
        cancelButton = tk.Button(master= self.quitDialog ,
                                text='Cancel',
                                command = self.quitALL).grid(row=2, column=1)

    def start(self):
        # self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
        self.quitDialog.wait_window()

    def quitALL(self):

        self.quitDialog.destroy()
        tc =TimeConverter()
        tc.destroyit()



class TimeConverter:
    def __init__(self):
        self.mainWindow = tk.Tk()
        self.mainWindow.title("Seconds Converter")
        self.results = tk.StringVar()
        self.inputSecs = tk.StringVar()
        secLabel = tk.Label(master=self.mainWindow,
                            text="Seconds:").grid(row=0, sticky="W")
        resultLabel = tk.Label(master=self.mainWindow,
                               text="Converted Time:n(H:M:S)").grid(row=1, sticky="W")
        calcResults = tk.Label(master=self.mainWindow,
                               background='light gray', width=20,
                               textvariable=self.results,
                               anchor="w").grid(row=1, column=1)
        secEntry = tk.Entry(master=self.mainWindow,
                            width=24,
                            textvariable=self.inputSecs).grid(row=0, column=1)

        calcButton = tk.Button(master=self.mainWindow,
                               text='Calculate',
                               command=self.SecondsToHours).grid(row=2,
                                                                 column=0, sticky="w")
        # quitButton = tk.Button(master=self.mainWindow,
        #                        text='Quit',
        #                        command=self.mainWindow.destroy).grid(row=2, column=1, sticky="E")
        quitButton = tk.Button(master=self.mainWindow,
                               text='Quit',
                               command=self.showQuitDialog).grid(row=3, column=1, sticky="E")

    def invalidInputEntered(self):
        errorDiag = AlertDialog()
        errorDiag.start()

    def showQuitDialog(self):
        quitdialog = QuitDialog()
        quitdialog.start()


    def startDisplay(self) -> None:
        self.mainWindow.mainloop()

    def destroyit(self):
        self.mainWindow.destroy()

    def SecondsToHours(self):
        try:
            inputseconds = int(self.inputSecs.get())
            seconds = int(inputseconds % 60)
            minutes = int(((inputseconds - seconds) / 60) % 60)
            hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
            tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
            self.results.set(tempResults)
            return

        except ValueError:
            self.invalidInputEntered()
            #self.showQuitDialog()


if __name__ == '__main__':
    TimeConverter().startDisplay()
Asked By: Samun

||

Answers:

You are importing tkinter 2 times here. Onces with * and ones as tk.

Just use:

import tkinter as tk

this will help you avoid overriding anything that other libraries imports or having tkinter’s functions overwritten by other imports.

You have a very unorthodox way of creating your tkinter app but if you wish to keep everything as is here is what you need to change:

Lets remove the cancel button from your quitDialog window and then add a yes and no button. This will server to allow you to either say yes to destroy all windows or to say no to only destroy the quitDialog window.

First we need to add an arguement to your QuitDialog class so we can pass the any window or frame we want to it.

So add the instance argument to your QuitDialog() class like below:

class  QuitDialog():

    def __init__(self, instance):
        self.instance = instance

Now replace:

cancelButton = tk.Button(master= self.quitDialog ,
                                text='Cancel',
                                command = self.quitALL).grid(row=2, column=1)

With:

quitButton = tk.Button(master= self.quitDialog ,
                       text='Yes', command = self.quitALL).grid(row=2, column=1)
cancelButton = tk.Button(master= self.quitDialog,
                         text='No', command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)

Then lets change your quitALL() method to:

def quitALL(self):
    self.quitDialog.destroy()
    self.instance.destroy()

This will use our instance argument to destroy a window we pass in.

Now change your showQuitDialog() method to:

def showQuitDialog(self):
    quitdialog = QuitDialog(self.mainWindow)
    quitdialog.start()

As you can see we are now passing the the tk window self.mainWindow to the QuitDialog class so we can decide on weather or not to close it.

Below is the copy past version of your code that should work as you need it to:

import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
import datetime


class AlertDialog:

    def __init__(self):

        self.invalidDiag = tk.Toplevel()
        invalidInput = tk.Label(master=self.invalidDiag,
                                text='Error: Invalid Input').grid(row=1, column=1)
        closeButton = tk.Button(master=self.invalidDiag,
                                text='Close',
                                command=self.invalidDiag.destroy).grid(row=2, column=1)

    def start(self):
        # self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
        self.invalidDiag.wait_window()


class  QuitDialog():

    def __init__(self, instance):

        self.instance = instance

        self.quitDialog = tk.Toplevel()

        warnMessage = tk.Label(master=self.quitDialog,
                                text='Are you sure that you want to quit? ').grid(row=1, column=1, columnspan=2)
        quitButton = tk.Button(master= self.quitDialog ,
                                text='Yes',
                                command = self.quitALL).grid(row=2, column=1)
        cancelButton = tk.Button(master= self.quitDialog,
                                text='No',
                                command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)

    def start(self):
        # self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
        self.quitDialog.wait_window()

    def quitALL(self):
        self.quitDialog.destroy()
        self.instance.destroy()


class TimeConverter:

    def __init__(self):

        self.mainWindow = tk.Tk()
        self.mainWindow.title("Seconds Converter")
        self.results = tk.StringVar()
        self.inputSecs = tk.StringVar()
        secLabel = tk.Label(master=self.mainWindow,
                            text="Seconds:").grid(row=0, sticky="W")
        resultLabel = tk.Label(master=self.mainWindow,
                               text="Converted Time:n(H:M:S)").grid(row=1, sticky="W")
        calcResults = tk.Label(master=self.mainWindow,
                               background='light gray', width=20,
                               textvariable=self.results,
                               anchor="w").grid(row=1, column=1)
        secEntry = tk.Entry(master=self.mainWindow,
                            width=24,
                            textvariable=self.inputSecs).grid(row=0, column=1)

        calcButton = tk.Button(master=self.mainWindow,
                               text='Calculate',
                               command=self.SecondsToHours).grid(row=2,
                                                                 column=0, sticky="w")
        quitButton = tk.Button(master=self.mainWindow,
                               text='Quit',
                               command=self.showQuitDialog).grid(row=3, column=1, sticky="E")

    def invalidInputEntered(self):
        errorDiag = AlertDialog()
        errorDiag.start()

    def showQuitDialog(self):
        quitdialog = QuitDialog(self.mainWindow)
        quitdialog.start()

    def startDisplay(self) -> None:
        self.mainWindow.mainloop()

    def destroyit(self):
        self.mainWindow.destroy()

    def SecondsToHours(self):
        try:
            inputseconds = int(self.inputSecs.get())
            seconds = int(inputseconds % 60)
            minutes = int(((inputseconds - seconds) / 60) % 60)
            hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
            tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
            self.results.set(tempResults)
            return

        except ValueError:
            self.invalidInputEntered()
            #self.showQuitDialog()

if __name__ == '__main__':
    TimeConverter().startDisplay()
Answered By: Mike – SMT

Interesting question. As I know, you can also use just quit() in order to quit from program by closing everything.

quit()

Answered By: Kamran-Dev
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.