1

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?

2
  • 1
    Unrelated to your question. You are aware that frame.pack is not a function call and does not pack anything, aren't you? Commented May 7, 2018 at 21:35
  • 3
    You didn't call Frame.__init__(self, master). Another problem is that your button commands are wrong. Change command = self.Print() to command = self.Print, otherwise the function is called immediately and the command is set to the return value of the function. Commented May 7, 2018 at 21:35

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.