1

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()
Samun
  • 151
  • 1
  • 1
  • 12
  • Welcome to StackOverflow! Please provide a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). You do not need to provide your full code. Just enough to show an example of your issue. The rest just gets in the way of people being able to help you. On that note I can tell you that your current code does not open new windows at least when I copy pasted the code to test it. – Mike - SMT Aug 23 '17 at 20:45
  • you need to call `destroy` on `self.mainWindow` if you want to literally destroy all of the windows. – Bryan Oakley Aug 23 '17 at 20:45
  • Possible duplicate of [How do I get rid of Python Tkinter root window?](https://stackoverflow.com/questions/1406145/how-do-i-get-rid-of-python-tkinter-root-window) – C8H10N4O2 Aug 23 '17 at 20:46
  • sorry if my question was unclear. In my QuitDialog Class, there is a button called cancel. I want that button to close all the windows. – Samun Aug 23 '17 at 20:56
  • @SamThapa: I have updated my answer let me know if you have any questions. – Mike - SMT Aug 23 '17 at 21:06

2 Answers2

3

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()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
0

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

quit()