19

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.

19

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.

For example, consider a simple example (assuming that tkinter has been imported like import tkinter as tk (python3) or import Tkinter as tk (python2):

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.

  • 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? – multigoodverse Apr 10 '16 at 7:06
  • 2
    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. . – Bryan Oakley Apr 10 '16 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/… – multigoodverse Apr 10 '16 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")" – user3885927 May 23 '16 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! – Bryan Oakley May 23 '16 at 16:21

protected by gnat Dec 23 '16 at 23:00

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.