22

I program primarily in python and have programmed a couple of GUI's with Tkinter, every tutorial I have ever seen has recommended defining and using a class for the GUI, but my GUI runs flawlessly using only procedures, without a class.

Why use a class? It seems from my perspective to simply be an extra layer of complexity and unnecessary code.

1 Answer 1

25

Why use a class? Because it makes the job easier, assuming you know how to do object oriented programming, and assuming you're writing a non-trivial GUI. Using objects allows you to easily divide your code into modular units that are self contained, and modularizing your code is generally considered to be a best practice.

GUI programming readily lends itself to an object-oriented style, since a GUI is made up entirely of objects -- labels, buttons, scrollbars, text areas, etc. Since you're already using objects, organizing your code into larger objects makes sense. The toolbar is an object, the statusbar is an object, the navigation pane is an object, the main area is an object, each notebook tab is an object, and so on.

Even when your code isn't very complex, from a more practical standpoint it lets you define bindings and callbacks earlier in the file than the definition of the function you're calling, which I think makes a lot of sense.

Consider a simple example:

import tkinter as tk

def quit(event=None):
    sys.exit()

root = tk.Tk()
label = tk.Label(root, text="Hello, world")
label.pack()
label.bind("<1>", quit)
root.mainloop()

To me, the flow of that code is all wrong. I have to define the quit method before I reference it, and the creation of the root window and the call to mainloop are separated by all of the other code.

By using classes, however, I can write the code in a more natural order:

class MyWindow(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Hello, world")
        label.pack()
        label.bind("<1>", self.quit)

    def quit(self, event=None):
        sys.exit()

root = tk.Tk()
MyWindow(root).pack()
root.mainloop()

The main body of the GUI is right at the top of the file, and supporting code is below it. Now, of course, you can use functions to achieve much of the same thing. In my opinion, though, classes make it all just a little easier.

Another advantage is that I can now easily change the containing window without having to change anything about the "main" window (and visa versa). That is, I can add borders, or a complete new section to the main GUI, but I don't have to touch a single line of code inside of MyWindow. Contrast that with the procedural code where you might have to change the label.pack() statement, and the pack (or grid) statements of all of the other widgets in the UI.

All that being said, however, using an object oriented approach isn't necessary to write good, clean, maintainable code. It can be, but it can also lead to poor code. At the end of the day, an object-oriented approach is just a tool. Whether you use it or not, and whether you use it correctly or not depends on a lot of factors. So it may very well be that for you, and for the code you write, a functional style is perfectly acceptable. I do think you'll find that as your programs get more complex, an object-oriented approach will make it easier to organize and maintain your code.

8
  • Why did you use a Frame in the second example? Couldn't you avoid it like you did in the first example? Is there any secret behind using Frame with classes? Commented Apr 10, 2016 at 7:06
  • 3
    The frame is simply for convenience. There is no secret to inheriting from Frame. I could have inherited from object or any other class, but I typically end up creating a frame anyway. If I'm putting everything in a frame, it makes sense to make the class a frame. . Commented Apr 10, 2016 at 8:19
  • 1
    Makes sense, thanks! Also, I have seen others use self before variables, but I see you're using something like label=tk.Label() instead of self.tk.Label(). Is that a style choice? Here is an example using self: python-textbok.readthedocs.org/en/1.0/… Commented Apr 10, 2016 at 10:47
  • 1
    @BryanOakley, I guess you meant to use parent instead of root in the following line of the MyWindow.__init__: "label = tk.Label(root, text="Hello, world")" Commented May 23, 2016 at 16:13
  • 1
    @user3885927: yes! Wow, it took almost three years for someone to notice that. Though, not parent but rather self, since the class itself is a Frame. Thanks! Commented May 23, 2016 at 16:21

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.