Search code examples
pythonfunctionclasstkinterinstance

Should I create a Tkinter instance from a class or a function?


I am a programmer who recently switched to Python, now working on a Tkinter application. Researching tkinter examples, I found my fellow programmers define tkinter either in a class or in a function.

What is the best choice and why? or In what kind of application would I choose to create it from class? And what scenario would be better for using just a function?

(I am working on a simple reusable Tkinter framework)

Thank you in advance for your answers and comments!

I tried both methods and both seem to work. But maybe as the application gets bigger I might run into problems?


Solution

  • While this question is teetering on the brink of being "opinion-based", I'll bite! For small projects (applications built around a single Python file, perhaps), you may find that the non-object-oriented "functional" approach is easier to deal with and suitable for your needs. That said, for most GUI application projects (of any size), I prefer to stick to the object-oriented approach using classes.

    I find that classes make it easier to compartmentalize things and improve code reusability. For example, I might create a custom widget class that inherits from a simpler built in widget. Or I might create a custom widget that inherits from tkinter.Frame and contains a number of other widgets - like an indicator with a text label, or a textbox with a built in character count...you get the idea.

    While OOP in tkinter may seem more complex at first, it also comes with greater flexibility and allows for cleaner code overall.

    Here are basic "boilerplate" tkinter applications using both approaches. You'll notice that there are several similarities between the two.

    Functional Approach

    import tkinter as tk
    
    
    root = tk.Tk()  # instantiate Tk - this is your main window
    # create a label widget as a child of 'root'
    label = tk.Label(root, text='Hello, World!')  
    label.pack()
    
    
    if __name__ == '__main__':
        root.mainloop()  # run the app
    

    Object-Oriented Approach

    import tkinter as tk
    
    
    class App(tk.Tk):  # define a class that inherits from Tk
        def __init__(self):  # this method runs when you instantiate your App class
            super().__init__()  # initialize Tk (similar to 'root = tk.Tk()' above)
            # create a label widget that's a member of this App class
            self.label = tk.Label(self, text='Hello, World!')
            self.label.pack()
    
    
    if __name__ == '__main__':
        root = App()  # instantiate your class - this runs your __init__ method
        root.mainloop()  # run the application 
        # instances of App have access to 'mainloop' because App inherits from Tk,
        # just like 'root' in the first example!
    

    Both of these applications will work in the same way, and look identical to the end user. Ultimately, there is no right or wrong way. There are always multiple approaches - the one you choose will depend on your needs! I hope that helps!

    Note that for brevity's sake I'm leaving out things like geometry and setting the title of the application window...you would normally want to do these things!