Search code examples
pythontkinter

Python tkinter root close


As an interim to my full application, I'm closing the window with buttons at different places in the file. Now originally, it works fine: I can close the application from both location within the file. However, I'm trying to clean the code up and have a better style.

Here's the code I have (with the better style):

from tkinter import *
from tkinter import ttk

class Location:
    def __init__(self, root):
        
        root.title("Location")
        root.geometry('400x295')  
 
        self.mainframe = ttk.Frame(root, padding="3 3 12 12")
        self.mainframe.grid(column = 0, row=0, sticky=(N, W, E, S))
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)

        confirm_button = ttk.Button(self.mainframe, text = 'CONFIRM', command = self.make_confirmation)
        confirm_button.grid(column=0, row=0)
        
        select_button = ttk.Button(self.mainframe, text = 'Geometry', command = root.quit)
        select_button.grid(column=0, row=1)  
        
    def make_confirmation(self, *args):
        root.quit()
        

def main_app():
    root = Tk()
    Location(root)
    root.mainloop()  
  
if __name__ == "__main__":
    main_app()

The "Geometry" button will close just fine.

The "Confirm" button gives me a NameError.

Note, def make_confirmation is in class Location

Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "c:\Users\User\Documents\Python\Tutorials\Quit_wStyle.py", line 22, in make_confirmation
    root.quit()
    ^^^^
NameError: name 'root' is not defined

In my non-MWE, make.confirmation does a bit more and has arguments passed through. That all works fine. I know that because when I get rid of def main_app(): and put it all in if __name__ == "__main__":, then both root.quit works.

In other words, this works:

from tkinter import *
from tkinter import ttk

class Location:
    def __init__(self, root):
        
        root.title("Location")
        root.geometry('400x295')  
 
        self.mainframe = ttk.Frame(root, padding="3 3 12 12")
        self.mainframe.grid(column = 0, row=0, sticky=(N, W, E, S))
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)

        confirm_button = ttk.Button(self.mainframe, text = 'CONFIRM', command = self.make_confirmation)
        confirm_button.grid(column=0, row=0)
        
        select_button = ttk.Button(self.mainframe, text = 'Geometry', command = root.quit)
        select_button.grid(column=0, row=1)  
        
    def make_confirmation(self, *args):
        root.quit()
  
if __name__ == "__main__":
    main_app()
    root = Tk()
    Location(root)
    root.mainloop()  

Why is command = root.quit working?

But command = self.make_confirmation does work?


Solution

  • Your root variable is scoped only for init function. If you want it to be available for the whole class, put self.root = root inside the init function. And refer to it as such in other functions of your class. if __name__ == "__main__": works because root variable is scoped to the whole file so you can get it everywhere in any function, but when you define it inside a function it is scoped to that function only, ergo variable cannot be accessed from anywhere else (you can fix it by adding global root)