Tkinter doesn't stop execution even after closing the window

Question:

In this code I am displaying a window with a label and two buttons, the user can read the file path currently in use in the label and decide if he wants to change it or continue with the buttons.

If he wants to change the path then I change the value inside the textvariable inside the label. The issue is when I do this for example 3 times, then I have to kill the program manually pressing CTRL + C 3 times. If I do it once then I only need to do it once, like there is something preventing the program to terminate. Thanks for the help.

def select_file():
    #OPEN TKINTER DIALOG LETTING ME TO CHOOSE A FILE AND RETURNS ITS PATH.
    tkinter.Tk().withdraw()  # prevents an empty tkinter window from appearing
    folder_path = filedialog.askopenfilename()
    return folder_path


def change_file():
    file_path = select_file()
    with open(os.path.expanduser('~/Documents/Squad Generator/excel_file_path.txt'), 'w') as f:
        f.write(file_path)
    #WRITES THE FILE PATH IN THE VARIABLE AND CHANGES THE LABEL
    var.set(file_path)

def homepage():

    app.geometry("450x200")
    app.title("Squad Generator")

    label_1 = tkinter.Label(master=app, justify=tkinter.LEFT,textvariable=var, font = 
       ("JetBrains Mono", 15))
    label_1.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")


    button1 = tkinter.Button(master=app, text="Continua", command=main)
    button1.grid(row=1, column=0, padx=20, pady=20, sticky="ew")
    
    #BUTTON CAUSING THE ISSUE.
    button2 = tkinter.Button(master=app, command=change_file, text="Cambia file")
    button2.grid(row=1, column=1, padx=0, pady=20, sticky="ew")
    
    #CREATING APP MAINLOOP
    app.mainloop()


if __name__ == '__main__':
    app = tkinter.Tk()
    var = tkinter.StringVar(None, check_path_file())
    homepage()
Asked By: emanuele pascale

||

Answers:

From what I see you just did

app.destroy()

But you actually need to do

app.master.destroy()

With the first line you’re just destroying the current frame, not the the top level container.

Answered By: Seka

I’ve reorganized your application a bit. I’ve wrapped everything in a basic class named App which serves as the root of your application. This should work as expected and keep everything contained within a single instance of Tk.

import tkinter
from tkinter.filedialog import askopenfilename


class App(tkinter.Tk):  # the App class inherits from Tk
    def __init__(self):
        super().__init__()  # initialize Tk
        self.geometry("450x200")
        self.title("Squad Generator")

        self.label_var=tkinter.StringVar(self, 'Select a file path')

        self.label_1 = tkinter.Label(
            master=self,
            justify=tkinter.LEFT,
            textvariable=self.label_var,
            font=("JetBrains Mono", 15)
        )
        self.label_1.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")

        self.button1 = tkinter.Button(master=self, text="Continua", command=main)
        self.button1.grid(row=1, column=0, padx=20, pady=20, sticky="ew")
    
        self.button2 = tkinter.Button(
            master=self,
            command=self.change_file,
            text="Cambia file"
        )
        self.button2.grid(row=1, column=1, padx=0, pady=20, sticky="ew")

        self.change_file()  # call this function when the app starts

    def change_file(self):
        file_path = askopenfilename()
        if file_path:  # if a file is selected and not cancelled by the user
            input_file = '~/Documents/Squad Generator/excel_file_path.txt'
        
            with open(os.path.expanduser(input_file), 'w') as f:
                f.write(file_path)  # write out 'file_path' to the 'input_file'
    
            #WRITES THE FILE PATH IN THE VARIABLE AND CHANGES THE LABEL
            self.label_var.set(file_path)
        else:
            self.label_var.set('Select a file path')  # fallback text if user cancels
  

if __name__ == '__main__':
    app = App()  # instantiate your App class
    app.mainloop()  # run the app

If you’re not familiar with classes, the word self here can be confusing. All you need to know is that self refers to the App class. So any widgets you define within that class, like button1 have self as their master – i.e., they are children of the App class!

Also, any methods you define within the class (like change_file(self)) will be callable within the class via self.change_file, and will have access to any variables in the class, like self.label_var!

Answered By: JRiggles
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.