Search code examples
pythonpython-3.xtkinterattributeerror

AttributeError: 'Application' object has no attribute 'tk'


I have the following script, which uses Tkinter:

import tkinter as tk

class Application(tk.Frame):    

    def __init__(self, master):
        frame = tk.Frame(master)
        frame.pack

        self.PRINT = tk.Button(frame, text = 'Print', fg = 'Red', command = self.Print())
        self.PRINT.pack(side = 'left')    

        self.QUIT = tk.Button(frame, text = 'Quit', fg = 'Red', command = self.quit())
        self.QUIT.pack(side = 'left')    

    def Print(self):
        print('at least somethings working')

root = tk.Tk()

b = Application(root)    
root.mainloop()

When I run it, I get the following error:

AttributeError: 'Application' object has no attribute 'tk'

Why do I get this error?


Solution

  • I ran your script here and got this stack trace:

    Traceback (most recent call last):
      File "t.py", line 23, in <module>
        b = Application(root)    
      File "t.py", line 15, in __init__
        self.QUIT = tk.Button(frame, text = 'Quit', fg = 'Red', command = self.quit())
      File "/usr/lib/python3.6/tkinter/__init__.py", line 1283, in quit
        self.tk.quit()
    AttributeError: 'Application' object has no attribute 'tk'
    

    The error message appears at the end but the entire stack is important! Let's analyze it.

    Apparently, there is an object, instance of an Application class, that has no tk attribute. Makes sense: we created this class, and we did not add this attribute.

    Well, the main loop expects an attribute to exist! What happens is, our class extends tkinter.Frame, and a frame need this tk attribute. Luckily, we do not have to think how to create it: since all frames need it, the frame initializer (its __init__() method) knows how to set this attribute.

    What we have to do, then, is just to call the tkinter.Frame initializer in our own initializer. This can be easily done by calling the __init__() directly from tk.Frame, passing the self variable:

    tk.Frame.__init__(self, master)
    

    The entire script will be this, then:

    import tkinter as tk
    
    class Application(tk.Frame):    
    
        def __init__(self, master):
            tk.Frame.__init__(self, master)
    
            frame = tk.Frame(master)
            frame.pack
    
            self.PRINT = tk.Button(frame, text = 'Print', fg = 'Red', command = self.Print())
            self.PRINT.pack(side = 'left')    
    
            self.QUIT = tk.Button(frame, text = 'Quit', fg = 'Red', command = self.quit())
            self.QUIT.pack(side = 'left')    
    
        def Print(self):
            print('at least somethings working')
    
    root = tk.Tk()
    
    b = Application(root)    
    root.mainloop()
    

    Now, there will be some other bugs in your script, you'll find soon ;) There is also some complications related to multiple inheritance that can be solved with the super() function. Nonetheless, this is the solution for your first bug.