0

In the official Python documentation (Python 3.7) there's the following example and I'm trying to understand how the code works. From original code I added some comments.

import tkinter as tk


class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)  # Initialize the tk.Frame class
        self.master = master  # Is it necessary?
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red", command=self.master.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")


def main():
    # Instance of the root window
    root = tk.Tk()
    # Instance of the main frame
    app = Application(master=root)
    # Infinite loop used to run the application
    app.mainloop()  # mainloop() on tk.Tk() instance (root) or tk.Frame() instance (app)?


if __name__ == '__main__':
    main()

I've two questions about this code:

  • After initialize tk.Frame class with super().__init__(master) in Application class, which inherits tk.Frame, self.master already contains reference to the root window. I verified that by printing id(self.master) before and after. So, is self.master = master necessary? Why was it added?
  • The mainloop() method is added to app instance of Application class, which inherits tk.Frame. But I could add the mainloop() method to root instance of tk.Tk class. The application works in both cases. What is the difference?
giusepped
  • 122
  • 3
  • 13

1 Answers1

1

self.master = master is not necessary for inheriting from tkinter classes. It is redundant in this case. Also you do not need master in super. Simply do super().__init__() will work here.

You should not use a geometry manager from within the frame to place itself on the parent container. Instead call it from outside the class. Say you need to change it from pack() to grid() you would have to change it in the class instead of simply updated its placement in the main code.

Your mainloop should be referencing the root instance.

I would pass all the initial parameters when creating the button. Its just adding more lines of code to update each parameter separately.

One last thing. If you are going to be editing a variable/widget later in your code then use self. prefix to make it a class attribute but if not there is no reason to use self. so we can remove them from the buttons.

Reworked code:

import tkinter as tk


class Application(tk.Frame):
    def __init__(self):
        super().__init__()
        tk.Button(self, text="Hello World\n(click me)", command=self.say_hi).pack(side="top")
        tk.Button(self, text="QUIT", fg="red", command=self.master.destroy).pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")


def main():
    root = tk.Tk()
    Application().pack()
    # app = MaxiTeam(root) # not sure what this is unless you meant Application?
    root.mainloop()


if __name__ == '__main__':
    main()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • 1
    _"Also you do not need master in super."_ I think that's bad advice. While it's not necessary in this specific case since the default is to put the frame in the root window, it's not true if you expect your class to be put inside anything other than root. The zen of python says explicit is better than implicit. – Bryan Oakley Nov 04 '19 at 17:46
  • @BryanOakley I have never had to do anything other than `super().__init__()` within classes that inherit from a tkinter widget. Typically I do not write any other inherited classes so I guess I have not had to deal with any case where it mattered. Can you point out an example where it is important? Also a largely accepted [post here](https://stackoverflow.com/a/576183/7475225) states"you can just say `super().__init__()` instead of `super(ChildB, self).__init__()` which IMO is quite a bit nicer." I admit I have not dug deeper as it appeared to be the accepted method. – Mike - SMT Nov 04 '19 at 18:00
  • @Mike-SMT I don't understand how _Application_ class knows who is the root window without passing the _root_ instance – giusepped Nov 04 '19 at 18:23
  • 2
    @Mike-SMT: in this example, in `main`, create a frame and then put `Application` inside of the frame rather than in root. eg `lf = tk.LabelFrame(root, text="Something"); Application(lf)`. If you don't pass `master` into `super.__init()`, the application will not be inside the labelframe. – Bryan Oakley Nov 04 '19 at 18:26
  • 2
    With `super` you don't need to specify the subclass, but you do need to pass on any configuration options, otherwise the base class has no way of seeing the configuration options. – Bryan Oakley Nov 04 '19 at 18:29