anukalp
anukalp

Reputation: 2790

Python and Tkinter: object oriented programming query

I am trying to learn python, Tkinter and oop. Below is the code that I wrote after following tutorial on effbot.org

    from Tkinter import Tk, Frame, Label

class Nexus(object):
    """Top level object which represents entire app"""
    def __init__(self, main_window):
        self.nexus_frame = Frame(main_window)
        self.nexus_frame.pack()

        self.label = Label(main_window, text="Tkinter")
        self.label.pack()





def main():
    main_window = Tk()
    nexus_app = Nexus(main_window)
    main_window.wm_title("Hello World Window")
    width = main_window.winfo_screenwidth()
    height = main_window.winfo_screenheight()
    main_window.wm_minsize(width=width-100, height=height-100)
    main_window.mainloop()

if __name__ == "__main__":
    main()

Here a top level window is created first and it is passed as argument to Nexus class where I am adding a frame and a label to the frame. Then I am setting the size of top level window relative to current screen size back in the main function.

My question is why was the top level window create in main function? Could it not be created inside __init__ of Nexus class itself? What difference would it make if main_window was create inside __init__ of Nexus class and mainloop() was started therein?

Upvotes: 1

Views: 1442

Answers (1)

sapi
sapi

Reputation: 10224

Once Tk.mainloop is entered, no further code will be executed. Instead, the Tk event loop will take over (hence the name).

What that means is that if you, eg, did something like this:

def main():
    ...
    main_window.mainloop()
    print 'Hello world!'

then that print statement would never be executed (or, at least, not while the GUI is running).


So, with that in mind, why is there a problem with creating the root window and executing main loop within the constructor (the __init__ statement)? Well, two basic reasons:

  • It would mean that the constructor never returns, which is unexpected. If a programmer sees this:

    def main():
        Nexus()
        print 'Hello world!'
    

    then he or she will expect that print statement to be executed. As a rule, you don't expect creating an instance of a class to be the kind of thing which will cause an infinite loop (as the event loop is).

  • Related to that is the second reason: it would not be possible to create more than one instance of Nexus, because as soon as you create one, Tk.mainloop will take over. Again, that's unexpected: a class is a description of a type of object, and you would normally expect to be able to instantiate more than one object like that.

    At the moment, if you write:

    def main():
        ...
        Nexus(main_window)
        Nexus(main_window)
    

    then you'll get two copies of your Nexus window on the screen. That's expected, and sensible. The alternative would not be.


So what's the take-away message?

When you're dealing with GUI programs, entering the event loop is the last thing you want to do. Your setup might involve creating one object (as now), or it might involve creating many objects (eg, a complex GUI app might have two or three windows).

Because we want to be able to write similar code in both cases, the usual approach is to create the root window (the Tk object) once, and then pass it in as a reference to any classes that need to know about it.

Upvotes: 3

Related Questions